1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-20 10:58:33 +00:00
Files
seahub/seahub/views/ajax.py

1467 lines
52 KiB
Python
Raw Normal View History

2013-07-27 17:07:44 +08:00
# -*- coding: utf-8 -*-
import os
import stat
import logging
import simplejson as json
from django.core.urlresolvers import reverse
2013-11-07 17:14:16 +08:00
from django.http import HttpResponse, Http404
2013-07-27 17:07:44 +08:00
from django.template import RequestContext
from django.template.loader import render_to_string
from django.utils.http import urlquote
from django.utils.translation import ugettext as _
import seaserv
from seaserv import seafile_api, seafserv_rpc, \
get_related_users_by_repo, get_related_users_by_org_repo, \
is_org_repo_owner, CALC_SHARE_USAGE, seafserv_threaded_rpc, \
get_user_quota_usage, get_user_share_usage
2013-07-27 17:07:44 +08:00
from pysearpc import SearpcError
from seahub.auth.decorators import login_required
from seahub.contacts.models import Contact
2013-07-27 17:07:44 +08:00
from seahub.forms import RepoNewDirentForm, RepoRenameDirentForm
from seahub.options.models import UserOptions, CryptoOptionNotSetError
from seahub.notifications.models import UserNotification
from seahub.signals import upload_file_successful
from seahub.views import get_repo_dirents, validate_owner, \
2014-01-21 16:30:07 +08:00
check_repo_access_permission, get_unencry_rw_repos_by_user, \
get_system_default_repo_id
from seahub.views.repo import get_nav_path, get_fileshare, get_dir_share_link, \
get_uploadlink, get_dir_shared_upload_link
2013-07-27 17:07:44 +08:00
import seahub.settings as settings
from seahub.signals import repo_deleted
from seahub.utils import check_filename_with_rename, EMPTY_SHA1, gen_block_get_url, \
check_and_get_org_by_repo, TRAFFIC_STATS_ENABLED, get_user_traffic_stat,\
new_merge_with_no_conflict, get_commit_before_new_merge, \
get_repo_last_modify, gen_file_upload_url
from seahub.utils.star import star_file, unstar_file
2013-07-27 17:07:44 +08:00
# Get an instance of a logger
logger = logging.getLogger(__name__)
########## Seafile API Wrapper
def get_repo(repo_id):
return seafile_api.get_repo(repo_id)
def get_commit(repo_id, repo_version, commit_id):
return seaserv.get_commit(repo_id, repo_version, commit_id)
2013-07-27 17:07:44 +08:00
def get_group(gid):
return seaserv.get_group(gid)
def is_group_user(gid, username):
return seaserv.is_group_user(gid, username)
2013-07-27 17:07:44 +08:00
########## repo related
@login_required
def get_dirents(request, repo_id):
"""
Get dirents in a dir for file tree
"""
if not request.is_ajax():
raise Http404
content_type = 'application/json; charset=utf-8'
username = request.user.username
# permission checking
user_perm = check_repo_access_permission(repo_id, request.user)
2013-07-27 17:07:44 +08:00
if user_perm is None:
err_msg = _(u"You don't have permission to access the library.")
return HttpResponse(json.dumps({"err_msg": err_msg}), status=403,
content_type=content_type)
path = request.GET.get('path', '')
dir_only = request.GET.get('dir_only', False)
all_dir = request.GET.get('all_dir', False)
2013-07-27 17:07:44 +08:00
if not path:
err_msg = _(u"No path.")
return HttpResponse(json.dumps({"err_msg": err_msg}), status=400,
content_type=content_type)
# get dirents for every path element
if all_dir:
all_dirents = []
path_eles = path.split('/')[:-1]
for i, x in enumerate(path_eles):
ele_path = '/'.join(path_eles[:i+1]) + '/'
try:
ele_path_dirents = seafile_api.list_dir_by_path(repo_id, ele_path.encode('utf-8'))
except SearpcError, e:
ele_path_dirents = []
ds = []
for d in ele_path_dirents:
if stat.S_ISDIR(d.mode):
ds.append(d.obj_name)
ds.sort(lambda x, y : cmp(x.lower(), y.lower()))
all_dirents.append(ds)
return HttpResponse(json.dumps(all_dirents), content_type=content_type)
# get dirents in path
2013-07-27 17:07:44 +08:00
try:
dirents = seafile_api.list_dir_by_path(repo_id, path.encode('utf-8'))
except SearpcError, e:
return HttpResponse(json.dumps({"err_msg": e.msg}), status=500,
content_type=content_type)
d_list = []
f_list = []
2013-07-27 17:07:44 +08:00
for dirent in dirents:
if stat.S_ISDIR(dirent.mode):
dirent.has_subdir = False
if dir_only:
dirent_path = os.path.join(path, dirent.obj_name)
try:
dirent_dirents = seafile_api.list_dir_by_path(repo_id, dirent_path.encode('utf-8'))
except SearpcError, e:
dirent_dirents = []
for dirent_dirent in dirent_dirents:
if stat.S_ISDIR(dirent_dirent.props.mode):
dirent.has_subdir = True
break
subdir = {
'name': dirent.obj_name,
'id': dirent.obj_id,
'type': 'dir',
'has_subdir': dirent.has_subdir, # to decide node 'state' ('closed' or not) in jstree
}
d_list.append(subdir)
2013-07-27 17:07:44 +08:00
else:
if not dir_only:
f = {
'id': dirent.obj_id,
'name': dirent.obj_name,
'type': 'file',
}
f_list.append(f)
2013-07-27 17:07:44 +08:00
d_list.sort(lambda x, y : cmp(x['name'].lower(), y['name'].lower()))
f_list.sort(lambda x, y : cmp(x['name'].lower(), y['name'].lower()))
return HttpResponse(json.dumps(d_list + f_list), content_type=content_type)
2013-07-27 17:07:44 +08:00
@login_required
def get_unenc_group_repos(request, group_id):
'''
Get unenc repos in a group.
'''
2013-07-27 17:07:44 +08:00
if not request.is_ajax():
raise Http404
content_type = 'application/json; charset=utf-8'
group_id_int = int(group_id)
group = get_group(group_id_int)
if not group:
err_msg = _(u"The group doesn't exist")
return HttpResponse(json.dumps({"err_msg": err_msg}), status=400,
content_type=content_type)
2013-07-27 17:07:44 +08:00
joined = is_group_user(group_id_int, request.user.username)
if not joined and not request.user.is_staff:
err_msg = _(u"Permission denied")
return HttpResponse(json.dumps({"err_msg": err_msg}), status=403,
content_type=content_type)
2013-07-27 17:07:44 +08:00
repos = seafile_api.get_group_repo_list(group_id_int)
repo_list = []
for repo in repos:
if not repo.encrypted:
repo_list.append({"name": repo.props.name, "id": repo.props.id})
repo_list.sort(lambda x, y : cmp(x['name'].lower(), y['name'].lower()))
2013-07-27 17:07:44 +08:00
return HttpResponse(json.dumps(repo_list), content_type=content_type)
@login_required
def get_my_unenc_repos(request):
"""Get my owned and unencrypted repos.
"""
2013-07-27 17:07:44 +08:00
if not request.is_ajax():
raise Http404
content_type = 'application/json; charset=utf-8'
repos = seafile_api.get_owned_repo_list(request.user.username)
2013-07-27 17:07:44 +08:00
repo_list = []
for repo in repos:
if repo.encrypted:
continue
repo_list.append({"name": repo.name, "id": repo.id})
2013-07-27 17:07:44 +08:00
2014-04-10 10:37:08 +08:00
repo_list.sort(lambda x, y : cmp(x['name'].lower(), y['name'].lower()))
2013-07-27 17:07:44 +08:00
return HttpResponse(json.dumps(repo_list), content_type=content_type)
2013-12-21 12:07:50 +08:00
@login_required
def unenc_rw_repos(request):
"""Get a user's unencrypt repos that he/she can read-write.
Arguments:
- `request`:
"""
if not request.is_ajax():
raise Http404
content_type = 'application/json; charset=utf-8'
username = request.user.username
acc_repos = get_unencry_rw_repos_by_user(username)
repo_list = []
for repo in acc_repos:
repo_list.append({"name": repo.name, "id": repo.id})
2014-04-10 10:37:08 +08:00
repo_list.sort(lambda x, y : cmp(x['name'].lower(), y['name'].lower()))
2013-12-21 12:07:50 +08:00
return HttpResponse(json.dumps(repo_list), content_type=content_type)
2013-07-27 17:07:44 +08:00
@login_required
def list_dir(request, repo_id):
"""
List directory entries in AJAX.
"""
if not request.is_ajax():
raise Http404
content_type = 'application/json; charset=utf-8'
2013-07-27 17:07:44 +08:00
repo = get_repo(repo_id)
if not repo:
err_msg = _(u'Library does not exist.')
return HttpResponse(json.dumps({'error': err_msg}),
status=400, content_type=content_type)
username = request.user.username
user_perm = check_repo_access_permission(repo.id, request.user)
2013-07-27 17:07:44 +08:00
if user_perm is None:
err_msg = _(u'Permission denied.')
return HttpResponse(json.dumps({'error': err_msg}),
status=403, content_type=content_type)
sub_lib_enabled = UserOptions.objects.is_sub_lib_enabled(username)
try:
server_crypto = UserOptions.objects.is_server_crypto(username)
except CryptoOptionNotSetError:
# Assume server_crypto is ``False`` if this option is not set.
2014-03-24 17:41:08 +08:00
server_crypto = False
if repo.encrypted and \
(repo.enc_version == 1 or (repo.enc_version == 2 and server_crypto)) \
and not seafile_api.is_password_set(repo.id, username):
2013-07-27 17:07:44 +08:00
err_msg = _(u'Library is encrypted.')
return HttpResponse(json.dumps({'error': err_msg}),
status=403, content_type=content_type)
head_commit = get_commit(repo.id, repo.version, repo.head_cmmt_id)
2013-07-27 17:07:44 +08:00
if not head_commit:
err_msg = _(u'Error: no head commit id')
return HttpResponse(json.dumps({'error': err_msg}),
status=500, content_type=content_type)
2014-03-24 17:41:08 +08:00
if new_merge_with_no_conflict(head_commit):
info_commit = get_commit_before_new_merge(head_commit)
else:
info_commit = head_commit
2013-07-27 17:07:44 +08:00
path = request.GET.get('p', '/')
if path[-1] != '/':
2014-03-24 17:41:08 +08:00
path = path + '/'
2013-07-27 17:07:44 +08:00
2013-08-20 18:30:17 +08:00
more_start = None
file_list, dir_list, dirent_more = get_repo_dirents(request, repo, head_commit, path, offset=0, limit=100)
2013-08-20 18:30:17 +08:00
if dirent_more:
more_start = 100
2013-07-27 17:07:44 +08:00
zipped = get_nav_path(path, repo.name)
fileshare = get_fileshare(repo.id, username, path)
dir_shared_link = get_dir_share_link(fileshare)
uploadlink = get_uploadlink(repo.id, username, path)
dir_shared_upload_link = get_dir_shared_upload_link(uploadlink)
2013-07-27 17:07:44 +08:00
ctx = {
'repo': repo,
'zipped': zipped,
'user_perm': user_perm,
'path': path,
'server_crypto': server_crypto,
2013-07-27 17:07:44 +08:00
'fileshare': fileshare,
'dir_shared_link': dir_shared_link,
'uploadlink': uploadlink,
'dir_shared_upload_link': dir_shared_upload_link,
2013-07-27 17:07:44 +08:00
'dir_list': dir_list,
'file_list': file_list,
2013-08-20 18:30:17 +08:00
'dirent_more': dirent_more,
'more_start': more_start,
2013-07-27 17:07:44 +08:00
'ENABLE_SUB_LIBRARY': settings.ENABLE_SUB_LIBRARY,
"sub_lib_enabled": sub_lib_enabled,
'current_commit': head_commit,
2014-03-24 17:41:08 +08:00
'info_commit': info_commit,
2013-07-27 17:07:44 +08:00
}
html = render_to_string('snippets/repo_dir_data.html', ctx,
context_instance=RequestContext(request))
return HttpResponse(json.dumps({'html': html, 'path': path}),
content_type=content_type)
2013-08-20 18:30:17 +08:00
@login_required
def list_dir_more(request, repo_id):
"""
List 'more' entries in a directory with AJAX.
"""
if not request.is_ajax():
raise Http404
content_type = 'application/json; charset=utf-8'
repo = get_repo(repo_id)
if not repo:
err_msg = _(u'Library does not exist.')
return HttpResponse(json.dumps({'error': err_msg}),
status=400, content_type=content_type)
username = request.user.username
user_perm = check_repo_access_permission(repo.id, request.user)
2013-08-20 18:30:17 +08:00
if user_perm is None:
err_msg = _(u'Permission denied.')
return HttpResponse(json.dumps({'error': err_msg}),
status=403, content_type=content_type)
sub_lib_enabled = UserOptions.objects.is_sub_lib_enabled(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
if repo.encrypted and \
(repo.enc_version == 1 or (repo.enc_version == 2 and server_crypto)) \
and not seafile_api.is_password_set(repo.id, username):
2013-08-20 18:30:17 +08:00
err_msg = _(u'Library is encrypted.')
return HttpResponse(json.dumps({'error': err_msg}),
status=403, content_type=content_type)
head_commit = get_commit(repo.id, repo.version, repo.head_cmmt_id)
2013-08-20 18:30:17 +08:00
if not head_commit:
err_msg = _(u'Error: no head commit id')
return HttpResponse(json.dumps({'error': err_msg}),
status=500, content_type=content_type)
path = request.GET.get('p', '/')
if path[-1] != '/':
path = path + '/'
offset = int(request.GET.get('start'))
if not offset:
err_msg = _(u'Argument missing')
return HttpResponse(json.dumps({'error': err_msg}),
status=400, content_type=content_type)
more_start = None
file_list, dir_list, dirent_more = get_repo_dirents(request, repo, head_commit, path, offset, limit=100)
2013-08-20 18:30:17 +08:00
if dirent_more:
more_start = offset + 100
ctx = {
'repo': repo,
'user_perm': user_perm,
'path': path,
'server_crypto': server_crypto,
2013-08-20 18:30:17 +08:00
'dir_list': dir_list,
'file_list': file_list,
'ENABLE_SUB_LIBRARY': settings.ENABLE_SUB_LIBRARY,
"sub_lib_enabled": sub_lib_enabled,
2013-08-20 18:30:17 +08:00
}
html = render_to_string('snippets/repo_dirents.html', ctx,
context_instance=RequestContext(request))
return HttpResponse(json.dumps({'html': html, 'dirent_more': dirent_more, 'more_start': more_start}),
content_type=content_type)
2013-07-27 17:07:44 +08:00
def new_dirent_common(func):
"""Decorator for common logic in creating directory and file.
"""
def _decorated(request, repo_id, *args, **kwargs):
if request.method != 'POST' or not request.is_ajax():
raise Http404
result = {}
content_type = 'application/json; charset=utf-8'
repo = get_repo(repo_id)
if not repo:
result['error'] = _(u'Library does not exist.')
return HttpResponse(json.dumps(result), status=400,
content_type=content_type)
# permission checking
username = request.user.username
if check_repo_access_permission(repo.id, request.user) != 'rw':
2013-07-27 17:07:44 +08:00
result['error'] = _('Permission denied')
return HttpResponse(json.dumps(result), status=403,
content_type=content_type)
# form validation
form = RepoNewDirentForm(request.POST)
if form.is_valid():
dirent_name = form.cleaned_data["dirent_name"]
else:
result['error'] = str(form.errors.values()[0])
return HttpResponse(json.dumps(result), status=400,
content_type=content_type)
# arguments checking
parent_dir = request.GET.get('parent_dir', None)
if not parent_dir:
result['error'] = _('Argument missing')
return HttpResponse(json.dumps(result), status=400,
content_type=content_type)
# rename duplicate name
dirent_name = check_filename_with_rename(repo.id, parent_dir,
dirent_name)
return func(repo.id, parent_dir, dirent_name, username)
return _decorated
@login_required
@new_dirent_common
def new_dir(repo_id, parent_dir, dirent_name, username):
"""
Create a new dir with ajax.
"""
result = {}
content_type = 'application/json; charset=utf-8'
# create new dirent
try:
seafile_api.post_dir(repo_id, parent_dir, dirent_name, username)
except SearpcError, e:
result['error'] = str(e)
return HttpResponse(json.dumps(result), status=500,
content_type=content_type)
return HttpResponse(json.dumps({'success': True, 'name': dirent_name}),
content_type=content_type)
@login_required
@new_dirent_common
def new_file(repo_id, parent_dir, dirent_name, username):
"""
Create a new file with ajax.
"""
result = {}
content_type = 'application/json; charset=utf-8'
# create new dirent
try:
seafile_api.post_empty_file(repo_id, parent_dir, dirent_name, username)
except SearpcError, e:
result['error'] = str(e)
return HttpResponse(json.dumps(result), status=500,
content_type=content_type)
return HttpResponse(json.dumps({'success': True, 'name': dirent_name}),
content_type=content_type)
@login_required
def rename_dirent(request, repo_id):
"""
Rename a file/dir in a repo, with ajax
"""
if request.method != 'POST' or not request.is_ajax():
raise Http404
result = {}
username = request.user.username
content_type = 'application/json; charset=utf-8'
repo = get_repo(repo_id)
if not repo:
result['error'] = _(u'Library does not exist.')
return HttpResponse(json.dumps(result), status=400,
content_type=content_type)
# permission checking
if check_repo_access_permission(repo.id, request.user) != 'rw':
2013-07-27 17:07:44 +08:00
result['error'] = _('Permission denied')
return HttpResponse(json.dumps(result), status=403,
content_type=content_type)
# form validation
form = RepoRenameDirentForm(request.POST)
if form.is_valid():
oldname = form.cleaned_data["oldname"]
newname = form.cleaned_data["newname"]
else:
result['error'] = str(form.errors.values()[0])
return HttpResponse(json.dumps(result), status=400,
content_type=content_type)
if newname == oldname:
return HttpResponse(json.dumps({'success': True}),
content_type=content_type)
# argument checking
parent_dir = request.GET.get('parent_dir', None)
if not parent_dir:
result['error'] = _('Argument missing')
return HttpResponse(json.dumps(result), status=400,
content_type=content_type)
# rename duplicate name
newname = check_filename_with_rename(repo_id, parent_dir, newname)
# rename file/dir
try:
seafile_api.rename_file(repo_id, parent_dir, oldname, newname, username)
except SearpcError, e:
result['error'] = str(e)
return HttpResponse(json.dumps(result), status=500,
content_type=content_type)
return HttpResponse(json.dumps({'success': True}),
content_type=content_type)
@login_required
def delete_dirent(request, repo_id):
"""
Delete a file/dir with ajax.
"""
if not request.is_ajax():
raise Http404
content_type = 'application/json; charset=utf-8'
repo = get_repo(repo_id)
if not repo:
err_msg = _(u'Library does not exist.')
return HttpResponse(json.dumps({'error': err_msg}),
status=400, content_type=content_type)
# permission checking
username = request.user.username
if check_repo_access_permission(repo.id, request.user) != 'rw':
2013-07-27 17:07:44 +08:00
err_msg = _(u'Permission denied.')
return HttpResponse(json.dumps({'error': err_msg}),
status=403, content_type=content_type)
# argument checking
parent_dir = request.GET.get("parent_dir", None)
dirent_name = request.GET.get("name", None)
if not (parent_dir and dirent_name):
err_msg = _(u'Argument missing.')
return HttpResponse(json.dumps({'error': err_msg}),
status=400, content_type=content_type)
# delete file/dir
try:
seafile_api.del_file(repo_id, parent_dir, dirent_name, username)
return HttpResponse(json.dumps({'success': True}),
content_type=content_type)
except SearpcError, e:
logger.error(e)
err_msg = _(u'Internal error. Failed to delete %s.') % dirent_name
return HttpResponse(json.dumps({'error': err_msg}),
status=500, content_type=content_type)
@login_required
def delete_dirents(request, repo_id):
"""
Delete multi files/dirs with ajax.
"""
if not request.is_ajax():
raise Http404
content_type = 'application/json; charset=utf-8'
repo = get_repo(repo_id)
if not repo:
err_msg = _(u'Library does not exist.')
return HttpResponse(json.dumps({'error': err_msg}),
status=400, content_type=content_type)
# permission checking
username = request.user.username
if check_repo_access_permission(repo.id, request.user) != 'rw':
err_msg = _(u'Permission denied.')
return HttpResponse(json.dumps({'error': err_msg}),
status=403, content_type=content_type)
# argument checking
parent_dir = request.GET.get("parent_dir")
dirents_names = request.POST.getlist('dirents_names')
if not (parent_dir and dirents_names):
err_msg = _(u'Argument missing.')
return HttpResponse(json.dumps({'error': err_msg}),
status=400, content_type=content_type)
deleted = []
undeleted = []
for dirent_name in dirents_names:
try:
seafile_api.del_file(repo_id, parent_dir, dirent_name, username)
deleted.append(dirent_name)
except SearpcError, e:
logger.error(e)
undeleted.append(dirent_name)
2013-11-07 17:14:16 +08:00
return HttpResponse(json.dumps({'deleted': deleted, 'undeleted': undeleted}),
content_type=content_type)
2013-07-27 17:07:44 +08:00
def copy_move_common(func):
"""Decorator for common logic in copying/moving dir/file.
"""
def _decorated(request, repo_id, *args, **kwargs):
if request.method != 'POST' or not request.is_ajax():
raise Http404
result = {}
content_type = 'application/json; charset=utf-8'
repo = get_repo(repo_id)
if not repo:
result['error'] = _(u'Library does not exist.')
return HttpResponse(json.dumps(result), status=400,
content_type=content_type)
# permission checking
username = request.user.username
if check_repo_access_permission(repo.id, request.user) != 'rw':
2013-07-27 17:07:44 +08:00
result['error'] = _('Permission denied')
return HttpResponse(json.dumps(result), status=403,
content_type=content_type)
# arguments validation
path = request.GET.get('path')
obj_name = request.GET.get('obj_name')
dst_repo_id = request.POST.get('dst_repo')
dst_path = request.POST.get('dst_path')
if not (path and obj_name and dst_repo_id and dst_path):
result['error'] = _('Argument missing')
return HttpResponse(json.dumps(result), status=400,
content_type=content_type)
# check file path
if len(dst_path+obj_name) > settings.MAX_PATH:
result['error'] = _('Destination path is too long.')
return HttpResponse(json.dumps(result), status=400,
content_type=content_type)
# check whether user has write permission to dest repo
if check_repo_access_permission(dst_repo_id, request.user) != 'rw':
2013-07-27 17:07:44 +08:00
result['error'] = _('Permission denied')
return HttpResponse(json.dumps(result), status=403,
content_type=content_type)
# do nothing when dst is the same as src
if repo_id == dst_repo_id and path == dst_path:
result['error'] = _('Invalid destination path')
return HttpResponse(json.dumps(result), status=400, content_type=content_type)
2013-07-27 17:07:44 +08:00
return func(repo_id, path, dst_repo_id, dst_path, obj_name, username)
return _decorated
@login_required
@copy_move_common
def mv_file(src_repo_id, src_path, dst_repo_id, dst_path, obj_name, username):
result = {}
content_type = 'application/json; charset=utf-8'
new_obj_name = check_filename_with_rename(dst_repo_id, dst_path, obj_name)
try:
res = seafile_api.move_file(src_repo_id, src_path, obj_name,
dst_repo_id, dst_path, new_obj_name, username, need_progress=1)
2013-07-27 17:07:44 +08:00
except SearpcError, e:
res = None
# res can be None or an object
if not res:
result['error'] = _(u'Internal server error')
2013-07-27 17:07:44 +08:00
return HttpResponse(json.dumps(result), status=500,
content_type=content_type)
result['success'] = True
msg_url = reverse('repo', args=[dst_repo_id]) + '?p=' + urlquote(dst_path)
msg = _(u'Successfully moved %(name)s <a href="%(url)s">view</a>') % \
{"name":obj_name, "url":msg_url}
result['msg'] = msg
if res.background:
result['task_id'] = res.task_id
return HttpResponse(json.dumps(result), content_type=content_type)
2013-07-27 17:07:44 +08:00
@login_required
@copy_move_common
def cp_file(src_repo_id, src_path, dst_repo_id, dst_path, obj_name, username):
result = {}
content_type = 'application/json; charset=utf-8'
new_obj_name = check_filename_with_rename(dst_repo_id, dst_path, obj_name)
try:
res = seafile_api.copy_file(src_repo_id, src_path, obj_name,
dst_repo_id, dst_path, new_obj_name, username, need_progress=1)
2013-07-27 17:07:44 +08:00
except SearpcError, e:
res = None
if not res:
result['error'] = _(u'Internal server error')
2013-07-27 17:07:44 +08:00
return HttpResponse(json.dumps(result), status=500,
content_type=content_type)
result['success'] = True
msg_url = reverse('repo', args=[dst_repo_id]) + '?p=' + urlquote(dst_path)
msg = _(u'Successfully copied %(name)s <a href="%(url)s">view</a>') % \
{"name":obj_name, "url":msg_url}
result['msg'] = msg
if res.background:
result['task_id'] = res.task_id
return HttpResponse(json.dumps(result), content_type=content_type)
2013-07-27 17:07:44 +08:00
@login_required
@copy_move_common
def mv_dir(src_repo_id, src_path, dst_repo_id, dst_path, obj_name, username):
result = {}
content_type = 'application/json; charset=utf-8'
2013-07-27 17:07:44 +08:00
src_dir = os.path.join(src_path, obj_name)
if dst_path.startswith(src_dir):
error_msg = _(u'Can not move directory %(src)s to its subdirectory %(des)s') \
% {'src': src_dir, 'des': dst_path}
result['error'] = error_msg
return HttpResponse(json.dumps(result), status=400, content_type=content_type)
new_obj_name = check_filename_with_rename(dst_repo_id, dst_path, obj_name)
try:
res = seafile_api.move_file(src_repo_id, src_path, obj_name,
dst_repo_id, dst_path, new_obj_name, username, need_progress=1)
2013-07-27 17:07:44 +08:00
except SearpcError, e:
res = None
# res can be None or an object
if not res:
result['error'] = _(u'Internal server error')
2013-07-27 17:07:44 +08:00
return HttpResponse(json.dumps(result), status=500,
content_type=content_type)
2013-07-27 17:07:44 +08:00
result['success'] = True
msg_url = reverse('repo', args=[dst_repo_id]) + '?p=' + urlquote(dst_path)
msg = _(u'Successfully moved %(name)s <a href="%(url)s">view</a>') % \
{"name":obj_name, "url":msg_url}
result['msg'] = msg
if res.background:
result['task_id'] = res.task_id
return HttpResponse(json.dumps(result), content_type=content_type)
2013-07-27 17:07:44 +08:00
@login_required
@copy_move_common
def cp_dir(src_repo_id, src_path, dst_repo_id, dst_path, obj_name, username):
result = {}
content_type = 'application/json; charset=utf-8'
2013-07-27 17:07:44 +08:00
src_dir = os.path.join(src_path, obj_name)
if dst_path.startswith(src_dir):
error_msg = _(u'Can not copy directory %(src)s to its subdirectory %(des)s') \
% {'src': src_dir, 'des': dst_path}
result['error'] = error_msg
return HttpResponse(json.dumps(result), status=400, content_type=content_type)
new_obj_name = check_filename_with_rename(dst_repo_id, dst_path, obj_name)
try:
res = seafile_api.copy_file(src_repo_id, src_path, obj_name,
dst_repo_id, dst_path, new_obj_name, username, need_progress=1)
2013-07-27 17:07:44 +08:00
except SearpcError, e:
res = None
# res can be None or an object
if not res:
result['error'] = _(u'Internal server error')
2013-07-27 17:07:44 +08:00
return HttpResponse(json.dumps(result), status=500,
content_type=content_type)
result['success'] = True
msg_url = reverse('repo', args=[dst_repo_id]) + '?p=' + urlquote(dst_path)
msg = _(u'Successfully copied %(name)s <a href="%(url)s">view</a>') % \
{"name":obj_name, "url":msg_url}
result['msg'] = msg
if res.background:
result['task_id'] = res.task_id
return HttpResponse(json.dumps(result), content_type=content_type)
2013-07-27 17:07:44 +08:00
def dirents_copy_move_common(func):
"""
Decorator for common logic in copying/moving dirs/files.
"""
def _decorated(request, repo_id, *args, **kwargs):
if request.method != 'POST' or not request.is_ajax():
raise Http404
result = {}
content_type = 'application/json; charset=utf-8'
repo = get_repo(repo_id)
if not repo:
result['error'] = _(u'Library does not exist.')
return HttpResponse(json.dumps(result), status=400,
content_type=content_type)
# permission checking
username = request.user.username
if check_repo_access_permission(repo.id, request.user) != 'rw':
result['error'] = _('Permission denied')
return HttpResponse(json.dumps(result), status=403,
content_type=content_type)
# arguments validation
parent_dir = request.GET.get('parent_dir')
obj_file_names = request.POST.getlist('file_names')
obj_dir_names = request.POST.getlist('dir_names')
dst_repo_id = request.POST.get('dst_repo')
dst_path = request.POST.get('dst_path')
if not (parent_dir and dst_repo_id and dst_path) and not (obj_file_names or obj_dir_names):
result['error'] = _('Argument missing')
return HttpResponse(json.dumps(result), status=400,
content_type=content_type)
# check file path
for obj_name in obj_file_names + obj_dir_names:
if len(dst_path+obj_name) > settings.MAX_PATH:
result['error'] = _('Destination path is too long for %s.') % obj_name
return HttpResponse(json.dumps(result), status=400,
content_type=content_type)
# check whether user has write permission to dest repo
if check_repo_access_permission(dst_repo_id, request.user) != 'rw':
result['error'] = _('Permission denied')
return HttpResponse(json.dumps(result), status=403,
content_type=content_type)
# when dst is the same as src
if repo_id == dst_repo_id and parent_dir == dst_path:
result['error'] = _('Invalid destination path')
return HttpResponse(json.dumps(result), status=400, content_type=content_type)
return func(repo_id, parent_dir, dst_repo_id, dst_path, obj_file_names, obj_dir_names, username)
return _decorated
@login_required
@dirents_copy_move_common
def mv_dirents(src_repo_id, src_path, dst_repo_id, dst_path, obj_file_names, obj_dir_names, username):
2013-11-07 17:14:16 +08:00
result = {}
content_type = 'application/json; charset=utf-8'
for obj_name in obj_dir_names:
src_dir = os.path.join(src_path, obj_name)
if dst_path.startswith(src_dir):
error_msg = _(u'Can not move directory %(src)s to its subdirectory %(des)s') \
% {'src': src_dir, 'des': dst_path}
result['error'] = error_msg
return HttpResponse(json.dumps(result), status=400, content_type=content_type)
success = []
failed = []
url = None
task_ids = []
for obj_name in obj_file_names + obj_dir_names:
new_obj_name = check_filename_with_rename(dst_repo_id, dst_path, obj_name)
try:
res = seafile_api.move_file(src_repo_id, src_path, obj_name,
dst_repo_id, dst_path, new_obj_name, username, need_progress=1)
except SearpcError, e:
res = None
if not res:
failed.append(obj_name)
else:
success.append(obj_name)
if res.background:
task_ids.append(res.task_id)
if len(success) > 0:
url = reverse('repo', args=[dst_repo_id]) + '?p=' + urlquote(dst_path)
result = {'success': success, 'failed': failed, 'url': url, 'task_ids': task_ids}
return HttpResponse(json.dumps(result), content_type=content_type)
@login_required
@dirents_copy_move_common
def cp_dirents(src_repo_id, src_path, dst_repo_id, dst_path, obj_file_names, obj_dir_names, username):
2013-11-07 17:14:16 +08:00
result = {}
content_type = 'application/json; charset=utf-8'
for obj_name in obj_dir_names:
src_dir = os.path.join(src_path, obj_name)
if dst_path.startswith(src_dir):
error_msg = _(u'Can not copy directory %(src)s to its subdirectory %(des)s') \
% {'src': src_dir, 'des': dst_path}
result['error'] = error_msg
return HttpResponse(json.dumps(result), status=400, content_type=content_type)
success = []
failed = []
url = None
task_ids = []
for obj_name in obj_file_names + obj_dir_names:
new_obj_name = check_filename_with_rename(dst_repo_id, dst_path, obj_name)
try:
res = seafile_api.copy_file(src_repo_id, src_path, obj_name,
dst_repo_id, dst_path, new_obj_name, username, need_progress=1)
except SearpcError, e:
res = None
if not res:
failed.append(obj_name)
else:
success.append(obj_name)
if res.background:
task_ids.append(res.task_id)
if len(success) > 0:
url = reverse('repo', args=[dst_repo_id]) + '?p=' + urlquote(dst_path)
result = {'success': success, 'failed': failed, 'url': url, 'task_ids': task_ids}
return HttpResponse(json.dumps(result), content_type=content_type)
@login_required
def get_cp_progress(request):
'''
Fetch progress of file/dir mv/cp.
'''
if not request.is_ajax():
raise Http404
content_type = 'application/json; charset=utf-8'
result = {}
task_id = request.GET.get('task_id')
if not task_id:
result['error'] = _(u'Argument missing')
return HttpResponse(json.dumps(result), status=400,
content_type=content_type)
res = seafile_api.get_copy_task(task_id)
# res can be None
if not res:
result['error'] = _(u'Error')
return HttpResponse(json.dumps(result), status=500, content_type=content_type)
result['done'] = res.done
result['total'] = res.total
result['canceled'] = res.canceled
result['failed'] = res.failed
result['successful'] = res.successful
return HttpResponse(json.dumps(result), content_type=content_type)
@login_required
def get_multi_cp_progress(request):
'''
Fetch progress of multi files/dirs mv/cp.
'''
if not request.is_ajax():
raise Http404
content_type = 'application/json; charset=utf-8'
result = {}
task_ids = request.GET.getlist('task_ids')
if not task_ids:
result['error'] = _(u'Argument missing')
return HttpResponse(json.dumps(result), status=400,
content_type=content_type)
success = 0
fail = 0
for task_id in task_ids:
res = seafile_api.get_copy_task(task_id)
if not res:
fail += 1
else:
if res.failed:
fail += 1
elif res.successful:
success += 1
result['success'] = success
result['fail'] = fail
return HttpResponse(json.dumps(result), content_type=content_type)
@login_required
def cancel_cp(request):
'''
cancel file/dir mv/cp.
'''
if not request.is_ajax():
raise Http404
content_type = 'application/json; charset=utf-8'
result = {}
task_id = request.GET.get('task_id')
if not task_id:
result['error'] = _('Argument missing')
return HttpResponse(json.dumps(result), status=400,
content_type=content_type)
res = seafile_api.cancel_copy_task(task_id) # returns 0 or -1
if res == 0:
result['success'] = True
return HttpResponse(json.dumps(result), content_type=content_type)
else:
result['error'] = _('Failed')
return HttpResponse(json.dumps(result), status=400,
content_type=content_type)
2013-07-27 17:07:44 +08:00
@login_required
def repo_star_file(request, repo_id):
if not request.is_ajax():
raise Http404
content_type = 'application/json; charset=utf-8'
path = request.GET.get('file', '')
if not path:
return HttpResponse(json.dumps({'error': _(u'Invalid arguments')}),
status=400, content_type=content_type)
is_dir = False
star_file(request.user.username, repo_id, path, is_dir)
return HttpResponse(json.dumps({'success':True}), content_type=content_type)
@login_required
def repo_unstar_file(request, repo_id):
if not request.is_ajax():
raise Http404
content_type = 'application/json; charset=utf-8'
path = request.GET.get('file', '')
if not path:
return HttpResponse(json.dumps({'error': _(u'Invalid arguments')}),
status=400, content_type=content_type)
unstar_file(request.user.username, repo_id, path)
return HttpResponse(json.dumps({'success':True}), content_type=content_type)
########## contacts related
@login_required
def get_contacts(request):
2013-07-27 17:07:44 +08:00
if not request.is_ajax():
raise Http404
content_type = 'application/json; charset=utf-8'
username = request.user.username
contacts = Contact.objects.get_contacts_by_user(username)
contact_list = []
from seahub.avatar.templatetags.avatar_tags import avatar
for c in contacts:
contact_list.append({"email": c.contact_email, "avatar": avatar(c.contact_email, 16)})
return HttpResponse(json.dumps({"contacts":contact_list}), content_type=content_type)
2013-07-27 17:07:44 +08:00
@login_required
def get_current_commit(request, repo_id):
if not request.is_ajax():
raise Http404
content_type = 'application/json; charset=utf-8'
repo = get_repo(repo_id)
if not repo:
err_msg = _(u'Library does not exist.')
return HttpResponse(json.dumps({'error': err_msg}),
status=400, content_type=content_type)
username = request.user.username
user_perm = check_repo_access_permission(repo.id, request.user)
if user_perm is None:
err_msg = _(u'Permission denied.')
return HttpResponse(json.dumps({'error': err_msg}),
status=403, content_type=content_type)
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
if repo.encrypted and \
(repo.enc_version == 1 or (repo.enc_version == 2 and server_crypto)) \
and not seafile_api.is_password_set(repo.id, username):
err_msg = _(u'Library is encrypted.')
return HttpResponse(json.dumps({'error': err_msg}),
status=403, content_type=content_type)
head_commit = get_commit(repo.id, repo.version, repo.head_cmmt_id)
if not head_commit:
err_msg = _(u'Error: no head commit id')
return HttpResponse(json.dumps({'error': err_msg}),
status=500, content_type=content_type)
2014-03-24 17:41:08 +08:00
if new_merge_with_no_conflict(head_commit):
2014-03-24 17:41:08 +08:00
info_commit = get_commit_before_new_merge(head_commit)
else:
info_commit = head_commit
ctx = {
'repo': repo,
2014-03-24 17:41:08 +08:00
'info_commit': info_commit
}
html = render_to_string('snippets/current_commit.html', ctx,
context_instance=RequestContext(request))
return HttpResponse(json.dumps({'html': html}),
content_type=content_type)
@login_required
2013-09-16 14:12:15 +08:00
def sub_repo(request, repo_id):
'''
check if a dir has a corresponding sub_repo
if it does not have, create one
'''
if not request.is_ajax():
raise Http404
content_type = 'application/json; charset=utf-8'
result = {}
path = request.GET.get('p')
name = request.GET.get('name')
if not (path and name):
result['error'] = _('Argument missing')
return HttpResponse(json.dumps(result), status=400, content_type=content_type)
2013-09-16 14:12:15 +08:00
username = request.user.username
# check if the sub-lib exist
try:
2013-09-16 14:12:15 +08:00
sub_repo = seafile_api.get_virtual_repo(repo_id, path, username)
except SearpcError, e:
result['error'] = e.msg
return HttpResponse(json.dumps(result), status=500, content_type=content_type)
if sub_repo:
result['sub_repo_id'] = sub_repo.id
else:
# create a sub-lib
try:
# use name as 'repo_name' & 'repo_desc' for sub_repo
2013-09-16 14:12:15 +08:00
sub_repo_id = seafile_api.create_virtual_repo(repo_id, path, name, name, username)
result['sub_repo_id'] = sub_repo_id
except SearpcError, e:
result['error'] = e.msg
return HttpResponse(json.dumps(result), status=500, content_type=content_type)
return HttpResponse(json.dumps(result), content_type=content_type)
def download_enc_file(request, repo_id, file_id):
if not request.is_ajax():
raise Http404
content_type = 'application/json; charset=utf-8'
result = {}
op = 'downloadblks'
blklist = []
if file_id == EMPTY_SHA1:
result = { 'blklist':blklist, 'url':None, }
return HttpResponse(json.dumps(result), content_type=content_type)
try:
blks = seafile_api.list_file_by_file_id(repo_id, file_id)
except SearpcError, e:
result['error'] = _(u'Failed to get file block list')
return HttpResponse(json.dumps(result), content_type=content_type)
blklist = blks.split('\n')
blklist = [i for i in blklist if len(i) == 40]
token = seafserv_rpc.web_get_access_token(repo_id, file_id,
op, request.user.username)
url = gen_block_get_url(token, None)
result = {
'blklist':blklist,
'url':url,
}
return HttpResponse(json.dumps(result), content_type=content_type)
def upload_file_done(request):
"""Send a message when a file is uploaded.
Arguments:
- `request`:
"""
ct = 'application/json; charset=utf-8'
result = {}
filename = request.GET.get('fn', '')
if not filename:
result['error'] = _('Argument missing')
return HttpResponse(json.dumps(result), status=400, content_type=ct)
repo_id = request.GET.get('repo_id', '')
if not repo_id:
result['error'] = _('Argument missing')
return HttpResponse(json.dumps(result), status=400, content_type=ct)
path = request.GET.get('p', '')
if not path:
result['error'] = _('Argument missing')
return HttpResponse(json.dumps(result), status=400, content_type=ct)
# a few checkings
if not seafile_api.get_repo(repo_id):
result['error'] = _('Wrong repo id')
return HttpResponse(json.dumps(result), status=400, content_type=ct)
owner = seafile_api.get_repo_owner(repo_id)
if not owner:
result['error'] = _('Wrong repo id')
return HttpResponse(json.dumps(result), status=400, content_type=ct)
file_path = path.rstrip('/') + '/' + filename
if seafile_api.get_file_id_by_path(repo_id, file_path) is None:
result['error'] = _('File does not exist')
return HttpResponse(json.dumps(result), status=400, content_type=ct)
# send singal
upload_file_successful.send(sender=None,
repo_id=repo_id,
file_path=file_path,
owner=owner)
return HttpResponse(json.dumps({'success': True}), content_type=ct)
@login_required
def unseen_notices_count(request):
"""Count user's unseen notices.
Arguments:
- `request`:
"""
if not request.is_ajax():
raise Http404
content_type = 'application/json; charset=utf-8'
username = request.user.username
count = UserNotification.objects.count_unseen_user_notifications(username)
result = {}
result['count'] = count
return HttpResponse(json.dumps(result), content_type=content_type)
@login_required
def repo_remove(request, repo_id):
if not request.is_ajax():
raise Http404
content_type = 'application/json; charset=utf-8'
result = {}
2014-01-21 16:30:07 +08:00
if get_system_default_repo_id() == repo_id:
result['error'] = _(u'System library can not be deleted.')
return HttpResponse(json.dumps(result), status=403, content_type=content_type)
repo = get_repo(repo_id)
if not repo:
result['error'] = _(u'Library does not exist')
return HttpResponse(json.dumps(result), status=400, content_type=content_type)
user = request.user.username
org, base_template = check_and_get_org_by_repo(repo_id, user)
if org:
# Remove repo in org context, only repo owner or org staff can
# perform this operation.
if request.user.is_staff or org.is_staff or \
is_org_repo_owner(org.org_id, repo_id, user):
# Must get related useres before remove the repo
usernames = get_related_users_by_org_repo(org.org_id, repo_id)
seafile_api.remove_repo(repo_id)
repo_deleted.send(sender=None,
org_id=org.org_id,
usernames=usernames,
repo_owner=user,
repo_id=repo_id,
repo_name=repo.name,
)
result['success'] = True
return HttpResponse(json.dumps(result), content_type=content_type)
else:
result['error'] = _(u'Permission denied.')
return HttpResponse(json.dumps(result), status=400, content_type=content_type)
else:
# Remove repo in personal context, only repo owner or site staff can
# perform this operation.
if validate_owner(request, repo_id) or request.user.is_staff:
usernames = get_related_users_by_repo(repo_id)
seafile_api.remove_repo(repo_id)
repo_deleted.send(sender=None,
org_id=-1,
usernames=usernames,
repo_owner=user,
repo_id=repo_id,
repo_name=repo.name,
)
result['success'] = True
return HttpResponse(json.dumps(result), content_type=content_type)
else:
result['error'] = _(u'Permission denied.')
return HttpResponse(json.dumps(result), status=400, content_type=content_type)
@login_required
def space_and_traffic(request):
if not request.is_ajax():
raise Http404
content_type = 'application/json; charset=utf-8'
result = {}
username = request.user.username
quota = seafserv_threaded_rpc.get_user_quota(username)
quota_usage = 0
share_usage = 0
my_usage = get_user_quota_usage(username)
rates = {}
if CALC_SHARE_USAGE:
share_usage = get_user_share_usage(username)
quota_usage = my_usage + share_usage
if quota > 0:
rates['my_usage'] = str(float(my_usage)/quota * 100) + '%'
rates['share_usage'] = str(float(share_usage)/quota * 100) + '%'
else:
quota_usage = my_usage
if quota > 0:
rates['quota_usage'] = str(float(my_usage)/quota * 100) + '%'
traffic_stat = 0
if TRAFFIC_STATS_ENABLED:
# User's network traffic stat in this month
try:
stat = get_user_traffic_stat(username)
except Exception as e:
logger.error(e)
stat = None
if stat:
traffic_stat = stat['file_view'] + stat['file_download'] + stat['dir_download']
ctx = {
"CALC_SHARE_USAGE": CALC_SHARE_USAGE,
"quota": quota,
"quota_usage": quota_usage,
"share_usage": share_usage,
"my_usage": my_usage,
"rates": rates,
"TRAFFIC_STATS_ENABLED": TRAFFIC_STATS_ENABLED,
"traffic_stat": traffic_stat,
"ENABLE_PAYMENT": getattr(settings, 'ENABLE_PAYMENT', False),
}
html = render_to_string('snippets/space_and_traffic.html', ctx,
context_instance=RequestContext(request))
return HttpResponse(json.dumps({"html": html}), content_type=content_type)
@login_required
def my_shared_and_group_repos(request):
"""Return html snippet of repos that shared to user and group repos.
Arguments:
- `request`:
"""
if not request.is_ajax():
raise Http404
content_type = 'application/json; charset=utf-8'
username = request.user.username
shared_repos = seafile_api.get_share_in_repo_list(username, -1, -1)
2014-03-13 18:16:04 +08:00
for repo in shared_repos:
repo.user_perm = seafile_api.check_repo_access_permission(repo.repo_id, username)
shared_repos.sort(lambda x, y: cmp(y.last_modified, x.last_modified))
group_repos = []
# Get all personal groups I joined.
joined_groups = request.user.joined_groups
# For each group I joined...
for grp in joined_groups:
# Get group repos, and for each group repos...
for r_id in seaserv.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 = seaserv.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 = seaserv.check_permission(r_id, username)
r.group = grp
group_repos.append(r)
group_repos.sort(key=lambda x: x.group.group_name)
for i, repo in enumerate(group_repos):
if i == 0:
repo.show_group_name = True
else:
if repo.group.group_name != group_repos[i-1].group.group_name:
repo.show_group_name = True
ctx_shared = {
"shared_repos": shared_repos,
}
ctx_group = {
"group_repos": group_repos,
}
shared_repos_html = render_to_string('snippets/my_shared_repos.html', ctx_shared,
context_instance=RequestContext(request))
group_repos_html = render_to_string('snippets/my_group_repos.html', ctx_group,
context_instance=RequestContext(request))
return HttpResponse(json.dumps({"shared": shared_repos_html, "group": group_repos_html}),
content_type=content_type)
@login_required
def get_file_op_url(request, repo_id):
"""Get file upload/update url for AJAX.
"""
if not request.is_ajax():
raise Http404
content_type = 'application/json; charset=utf-8'
op_type = request.GET.get('op_type') # value can be 'upload', 'update', 'upload-blks', 'update-blks'
if not op_type:
err_msg = _(u'Argument missing')
return HttpResponse(json.dumps({"error": err_msg}), status=400,
content_type=content_type)
username = request.user.username
url = ''
if check_repo_access_permission(repo_id, request.user) == 'rw':
token = seafile_api.get_httpserver_access_token(repo_id, 'dummy',
op_type, username)
url = gen_file_upload_url(token, op_type + '-aj')
return HttpResponse(json.dumps({"url": url}), content_type=content_type)