mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-02 23:48:47 +00:00
[api] clean code for http errors
This commit is contained in:
@@ -417,5 +417,13 @@ for line in mime_str.splitlines():
|
|||||||
if len(pair) == 2:
|
if len(pair) == 2:
|
||||||
MIME_MAP[pair[0]] = pair[1]
|
MIME_MAP[pair[0]] = pair[1]
|
||||||
|
|
||||||
|
|
||||||
|
def get_file_mime(name):
|
||||||
|
sufix = os.path.splitext(name)[1][1:]
|
||||||
|
if sufix:
|
||||||
|
return MIME_MAP[sufix]
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
print MIME_MAP
|
print MIME_MAP
|
||||||
|
@@ -1,13 +1,15 @@
|
|||||||
from django.conf.urls.defaults import *
|
from django.conf.urls.defaults import *
|
||||||
|
|
||||||
|
from django.views.decorators.csrf import csrf_exempt
|
||||||
|
|
||||||
from views import *
|
from views import *
|
||||||
|
|
||||||
|
|
||||||
urlpatterns = patterns('',
|
urlpatterns = patterns('',
|
||||||
url(r'^ping/$', Ping.as_view()),
|
url(r'^ping/$', Ping.as_view()),
|
||||||
url(r'login/$', api_login),
|
url(r'login/$', csrf_exempt(api_login)),
|
||||||
url(r'^$', ReposView.as_view()),
|
url(r'^$', csrf_exempt(ReposView.as_view())),
|
||||||
url(r'^repo/list/$', ReposView.as_view(), name='repos'),
|
url(r'^repo/list/$', csrf_exempt(ReposView.as_view()), name='repos'),
|
||||||
url(r'^repo/(?P<repo_id>[^/]+)/$', csrf_exempt(RepoView.as_view()), name='repo'),
|
url(r'^repo/(?P<repo_id>[^/]+)/$', csrf_exempt(RepoView.as_view()), name='repo'),
|
||||||
|
|
||||||
url(r'^dir/(?P<repo_id>[^/]+)/$', csrf_exempt(RepoDirPathView.as_view()), name='repo-dir-path'),
|
url(r'^dir/(?P<repo_id>[^/]+)/$', csrf_exempt(RepoDirPathView.as_view()), name='repo-dir-path'),
|
||||||
|
145
api/views.py
145
api/views.py
@@ -6,10 +6,9 @@ import stat
|
|||||||
import simplejson as json
|
import simplejson as json
|
||||||
import settings
|
import settings
|
||||||
|
|
||||||
from django.http import HttpResponse, HttpResponseServerError
|
from django.http import HttpResponse
|
||||||
from django.contrib.sites.models import RequestSite
|
from django.contrib.sites.models import RequestSite
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from django.views.decorators.csrf import csrf_exempt
|
|
||||||
from django.template import loader
|
from django.template import loader
|
||||||
|
|
||||||
from djangorestframework.renderers import JSONRenderer
|
from djangorestframework.renderers import JSONRenderer
|
||||||
@@ -17,7 +16,13 @@ from djangorestframework.compat import View
|
|||||||
from djangorestframework.mixins import ResponseMixin
|
from djangorestframework.mixins import ResponseMixin
|
||||||
from djangorestframework.response import Response
|
from djangorestframework.response import Response
|
||||||
|
|
||||||
from auth.decorators import api_login_required
|
|
||||||
|
try:
|
||||||
|
from functools import update_wrapper, wraps
|
||||||
|
except ImportError:
|
||||||
|
from django.utils.functional import update_wrapper, wraps # Python 2.4 fallback.
|
||||||
|
from django.utils.decorators import available_attrs
|
||||||
|
|
||||||
from auth.forms import AuthenticationForm
|
from auth.forms import AuthenticationForm
|
||||||
from auth import login as auth_login
|
from auth import login as auth_login
|
||||||
|
|
||||||
@@ -34,18 +39,73 @@ from seahub.utils import list_to_string, \
|
|||||||
|
|
||||||
from seahub.views import access_to_repo, validate_owner
|
from seahub.views import access_to_repo, validate_owner
|
||||||
from seahub.contacts.signals import mail_sended
|
from seahub.contacts.signals import mail_sended
|
||||||
|
|
||||||
from share.models import FileShare
|
from share.models import FileShare
|
||||||
|
|
||||||
from mime import MIME_MAP
|
from mime import get_file_mime
|
||||||
|
|
||||||
json_content_type = 'application/json; charset=utf-8'
|
json_content_type = 'application/json; charset=utf-8'
|
||||||
|
|
||||||
def get_file_mime(name):
|
HTTP_ERRORS = {
|
||||||
sufix = os.path.splitext(name)[1][1:]
|
'400':'Bad arguments',
|
||||||
if sufix:
|
'401':'Repo is not encrypted',
|
||||||
return MIME_MAP[sufix]
|
'402':'Incorrect password',
|
||||||
return None
|
'403':'Can not access repo',
|
||||||
|
'404':'Repo not found',
|
||||||
|
'405':'Query password set error',
|
||||||
|
'406':'Password needed',
|
||||||
|
'407':'Method not supported',
|
||||||
|
'408':'Login failed',
|
||||||
|
'410':'Path does not exist',
|
||||||
|
'411':'Failed to get dirid by path',
|
||||||
|
'412':'Failed to get fileid by path',
|
||||||
|
'413':'Path needed',
|
||||||
|
'414':'Emails required',
|
||||||
|
'415':'Operation not supported',
|
||||||
|
'416':'Failed to list dir',
|
||||||
|
'417':'Set password error',
|
||||||
|
|
||||||
|
'499':'Unknow Error',
|
||||||
|
|
||||||
|
'500':'Internal server error',
|
||||||
|
'501':'Failed to get shared link',
|
||||||
|
'502':'Failed to send shared link',
|
||||||
|
}
|
||||||
|
|
||||||
|
def api_error(request, code='499', msg=None):
|
||||||
|
err_resp = { 'error_msg': msg if msg is not None else HTTP_ERRORS[code] }
|
||||||
|
return HttpResponse(json.dumps(err_resp), status=code,
|
||||||
|
content_type=json_content_type)
|
||||||
|
|
||||||
|
def api_user_passes_test(test_func):
|
||||||
|
"""
|
||||||
|
Decorator for views that checks that the user passes the given test,
|
||||||
|
redirecting to the log-in page if necessary. The test should be a callable
|
||||||
|
that takes the user object and returns True if the user passes.
|
||||||
|
"""
|
||||||
|
def decorator(view_func):
|
||||||
|
def _wrapped_view(obj, request, *args, **kwargs):
|
||||||
|
if test_func(request.user):
|
||||||
|
return view_func(obj, request, *args, **kwargs)
|
||||||
|
json_content_type = 'application/json; charset=utf-8'
|
||||||
|
|
||||||
|
return HttpResponse(json.dumps('login required'), status=401,
|
||||||
|
content_type=json_content_type)
|
||||||
|
return wraps(view_func, assigned=available_attrs(view_func))(_wrapped_view)
|
||||||
|
return decorator
|
||||||
|
|
||||||
|
|
||||||
|
def api_login_required(function=None):
|
||||||
|
"""
|
||||||
|
Decorator for views that checks that the user is logged in, redirecting
|
||||||
|
to the log-in page if necessary.
|
||||||
|
"""
|
||||||
|
actual_decorator = api_user_passes_test(
|
||||||
|
lambda u: u.is_authenticated()
|
||||||
|
)
|
||||||
|
if function:
|
||||||
|
return actual_decorator(function)
|
||||||
|
return actual_decorator
|
||||||
|
|
||||||
|
|
||||||
def calculate_repo_info(repo_list, username):
|
def calculate_repo_info(repo_list, username):
|
||||||
"""
|
"""
|
||||||
@@ -76,11 +136,6 @@ def calculate_repo_info(repo_list, username):
|
|||||||
repo.size = -1
|
repo.size = -1
|
||||||
repo.password_need = None
|
repo.password_need = None
|
||||||
|
|
||||||
def api_error(request, code='404', msg=None):
|
|
||||||
err_resp = {'error_msg':msg}
|
|
||||||
return HttpResponse(json.dumps(err_resp), status=code,
|
|
||||||
content_type=json_content_type)
|
|
||||||
|
|
||||||
def can_access_repo(request, repo_id):
|
def can_access_repo(request, repo_id):
|
||||||
repo_ap = seafserv_threaded_rpc.repo_query_access_property(repo_id)
|
repo_ap = seafserv_threaded_rpc.repo_query_access_property(repo_id)
|
||||||
if not repo_ap:
|
if not repo_ap:
|
||||||
@@ -101,7 +156,8 @@ def get_dir_entrys_by_id(request, dir_id):
|
|||||||
try:
|
try:
|
||||||
dirs = seafserv_threaded_rpc.list_dir(dir_id)
|
dirs = seafserv_threaded_rpc.list_dir(dir_id)
|
||||||
except SearpcError, e:
|
except SearpcError, e:
|
||||||
return api_error(request, "404", e.msg)
|
return api_error(request, "416")
|
||||||
|
|
||||||
for dirent in dirs:
|
for dirent in dirs:
|
||||||
dtype = "file"
|
dtype = "file"
|
||||||
entry={}
|
entry={}
|
||||||
@@ -127,28 +183,28 @@ def get_dir_entrys_by_id(request, dir_id):
|
|||||||
|
|
||||||
def set_repo_password(request, repo, password):
|
def set_repo_password(request, repo, password):
|
||||||
if not password:
|
if not password:
|
||||||
return api_error(request, '400', 'password should not be empty')
|
return api_error(request, '406')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
seafserv_threaded_rpc.set_passwd(repo.id, request.user.username, password)
|
seafserv_threaded_rpc.set_passwd(repo.id, request.user.username, password)
|
||||||
except SearpcError, e:
|
except SearpcError, e:
|
||||||
if e.msg == 'Bad arguments':
|
if e.msg == 'Bad arguments':
|
||||||
return api_error(request, '400', e.msg)
|
return api_error(request, '400')
|
||||||
elif e.msg == 'Repo is not encrypted':
|
elif e.msg == 'Repo is not encrypted':
|
||||||
return api_error(request, '400', e.msg)
|
return api_error(request, '401')
|
||||||
elif e.msg == 'Incorrect password':
|
elif e.msg == 'Incorrect password':
|
||||||
return api_error(request, '400', 'Wrong password')
|
return api_error(request, '402')
|
||||||
elif e.msg == 'Internal server error':
|
elif e.msg == 'Internal server error':
|
||||||
return api_error(request, '500', e.msg)
|
return api_error(request, '500')
|
||||||
else:
|
else:
|
||||||
return api_error(request, '400', e.msg)
|
return api_error(request, '417', e.msg)
|
||||||
|
|
||||||
def check_repo_access_permission(request, repo):
|
def check_repo_access_permission(request, repo):
|
||||||
if not repo:
|
if not repo:
|
||||||
return api_error(request, '404', "repo not found")
|
return api_error(request, '404')
|
||||||
|
|
||||||
if not can_access_repo(request, repo.id):
|
if not can_access_repo(request, repo.id):
|
||||||
return api_error(request, '403', "can not access repo")
|
return api_error(request, '403')
|
||||||
|
|
||||||
password_set = False
|
password_set = False
|
||||||
if repo.encrypted:
|
if repo.encrypted:
|
||||||
@@ -157,30 +213,29 @@ def check_repo_access_permission(request, repo):
|
|||||||
if ret == 1:
|
if ret == 1:
|
||||||
password_set = True
|
password_set = True
|
||||||
except SearpcError, e:
|
except SearpcError, e:
|
||||||
return api_error(request, '403', e.msg)
|
return api_error(request, '405', e.msg)
|
||||||
|
|
||||||
if not password_set:
|
if not password_set:
|
||||||
password = request.REQUEST['password']
|
password = request.REQUEST['password']
|
||||||
if not password:
|
if not password:
|
||||||
return api_error(request, '403', "password needed")
|
return api_error(request, '406')
|
||||||
|
|
||||||
return set_repo_password(request, repo, password)
|
return set_repo_password(request, repo, password)
|
||||||
|
|
||||||
|
|
||||||
@csrf_exempt
|
|
||||||
def api_login(request):
|
def api_login(request):
|
||||||
if request.method == "POST" :
|
if request.method == "POST" :
|
||||||
form = AuthenticationForm(data=request.POST)
|
form = AuthenticationForm(data=request.POST)
|
||||||
else:
|
else:
|
||||||
return api_error(request, 400, "method not supported")
|
return api_error(request, '407')
|
||||||
|
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
auth_login(request, form.get_user())
|
auth_login(request, form.get_user())
|
||||||
return HttpResponse(json.dumps(request.session.session_key), status=200,
|
return HttpResponse(json.dumps(request.session.session_key), status=200,
|
||||||
content_type=json_content_type)
|
content_type=json_content_type)
|
||||||
else:
|
else:
|
||||||
return HttpResponse(json.dumps("failed"), status=401,
|
return api_error(request, '408')
|
||||||
content_type=json_content_type)
|
|
||||||
|
|
||||||
class Ping(ResponseMixin, View):
|
class Ping(ResponseMixin, View):
|
||||||
|
|
||||||
@@ -249,10 +304,10 @@ class RepoView(ResponseMixin, View):
|
|||||||
# check whether user can view repo
|
# check whether user can view repo
|
||||||
repo = get_repo(repo_id)
|
repo = get_repo(repo_id)
|
||||||
if not repo:
|
if not repo:
|
||||||
return api_error(request, '404', "repo not found")
|
return api_error(request, '404')
|
||||||
|
|
||||||
if not can_access_repo(request, repo.id):
|
if not can_access_repo(request, repo.id):
|
||||||
return api_error(request, '403', "can not access repo")
|
return api_error(request, '403')
|
||||||
|
|
||||||
# check whether use is repo owner
|
# check whether use is repo owner
|
||||||
if validate_owner(request, repo_id):
|
if validate_owner(request, repo_id):
|
||||||
@@ -316,7 +371,10 @@ class RepoDirPathView(ResponseMixin, View):
|
|||||||
dir_id = seafserv_threaded_rpc.get_dirid_by_path(current_commit.id,
|
dir_id = seafserv_threaded_rpc.get_dirid_by_path(current_commit.id,
|
||||||
path.encode('utf-8'))
|
path.encode('utf-8'))
|
||||||
except SearpcError, e:
|
except SearpcError, e:
|
||||||
return api_error(request, "404", e.msg)
|
return api_error(request, "411", e.msg)
|
||||||
|
|
||||||
|
if not dir_id:
|
||||||
|
return api_error(request, '410')
|
||||||
|
|
||||||
old_oid = request.GET.get('oid', None)
|
old_oid = request.GET.get('oid', None)
|
||||||
if old_oid and old_oid == dir_id :
|
if old_oid and old_oid == dir_id :
|
||||||
@@ -360,8 +418,7 @@ def get_shared_link(request, repo_id, path):
|
|||||||
try:
|
try:
|
||||||
fs.save()
|
fs.save()
|
||||||
except IntegrityError, e:
|
except IntegrityError, e:
|
||||||
err = '获取分享链接失败,请重新获取'
|
return api_err(request, '501')
|
||||||
return api_err(request, '500', err)
|
|
||||||
|
|
||||||
domain = RequestSite(request).domain
|
domain = RequestSite(request).domain
|
||||||
file_shared_link = 'http://%s%sf/%s/' % (domain,
|
file_shared_link = 'http://%s%sf/%s/' % (domain,
|
||||||
@@ -402,8 +459,7 @@ def send_share_link(request, repo_id, path, emails):
|
|||||||
try:
|
try:
|
||||||
fs.save()
|
fs.save()
|
||||||
except IntegrityError, e:
|
except IntegrityError, e:
|
||||||
err = '获取分享链接失败,请重新获取'
|
return api_err(request, '501')
|
||||||
return api_err(request, '500', err)
|
|
||||||
|
|
||||||
domain = RequestSite(request).domain
|
domain = RequestSite(request).domain
|
||||||
file_shared_link = 'http://%s%sf/%s/' % (domain,
|
file_shared_link = 'http://%s%sf/%s/' % (domain,
|
||||||
@@ -424,8 +480,7 @@ def send_share_link(request, repo_id, path, emails):
|
|||||||
t.render(Context(c)), None, [to_email],
|
t.render(Context(c)), None, [to_email],
|
||||||
fail_silently=False)
|
fail_silently=False)
|
||||||
except:
|
except:
|
||||||
err = 'Failed to send'
|
return api_error(request, '502')
|
||||||
return api_error(request, '406', err)
|
|
||||||
return HttpResponse(json.dumps(file_shared_link), status=200, content_type=json_content_type)
|
return HttpResponse(json.dumps(file_shared_link), status=200, content_type=json_content_type)
|
||||||
|
|
||||||
class RepoFileIdView(ResponseMixin, View):
|
class RepoFileIdView(ResponseMixin, View):
|
||||||
@@ -453,17 +508,17 @@ class RepoFilePathView(ResponseMixin, View):
|
|||||||
|
|
||||||
path = request.GET.get('p', None)
|
path = request.GET.get('p', None)
|
||||||
if not path:
|
if not path:
|
||||||
return api_error(request, '404', "Path invalid")
|
return api_error(request, '413')
|
||||||
|
|
||||||
file_id = None
|
file_id = None
|
||||||
try:
|
try:
|
||||||
file_id = seafserv_threaded_rpc.get_file_by_path(repo_id,
|
file_id = seafserv_threaded_rpc.get_file_by_path(repo_id,
|
||||||
path.encode('utf-8'))
|
path.encode('utf-8'))
|
||||||
except SearpcError, e:
|
except SearpcError, e:
|
||||||
return api_error(request, '404', e.msg)
|
return api_error(request, '412', e.msg)
|
||||||
|
|
||||||
if not file_id:
|
if not file_id:
|
||||||
return api_error(request, '400', "Path invalid")
|
return api_error(request, '410')
|
||||||
|
|
||||||
file_name = request.GET.get('file_name', file_id)
|
file_name = request.GET.get('file_name', file_id)
|
||||||
op = request.GET.get('op', 'download')
|
op = request.GET.get('op', 'download')
|
||||||
@@ -478,7 +533,7 @@ class RepoFilePathView(ResponseMixin, View):
|
|||||||
|
|
||||||
path = request.GET.get('p', None)
|
path = request.GET.get('p', None)
|
||||||
if not path:
|
if not path:
|
||||||
return api_error(request, '404', "Path invalid")
|
return api_error(request, '413')
|
||||||
|
|
||||||
op = request.GET.get('op', 'delete')
|
op = request.GET.get('op', 'delete')
|
||||||
if op == 'delete':
|
if op == 'delete':
|
||||||
@@ -486,8 +541,8 @@ class RepoFilePathView(ResponseMixin, View):
|
|||||||
if op == 'sendsharelink':
|
if op == 'sendsharelink':
|
||||||
emails = request.POST.get('email', None)
|
emails = request.POST.get('email', None)
|
||||||
if not emails:
|
if not emails:
|
||||||
return api_error(request, '400', 'emails required')
|
return api_error(request, '414')
|
||||||
return send_share_link(request, path, emails)
|
return send_share_link(request, path, emails)
|
||||||
|
|
||||||
return api_error(request, '404', 'operation not support')
|
return api_error(request, '415')
|
||||||
|
|
||||||
|
@@ -44,37 +44,6 @@ def login_required(function=None, redirect_field_name=REDIRECT_FIELD_NAME):
|
|||||||
return actual_decorator
|
return actual_decorator
|
||||||
|
|
||||||
|
|
||||||
def api_user_passes_test(test_func):
|
|
||||||
"""
|
|
||||||
Decorator for views that checks that the user passes the given test,
|
|
||||||
redirecting to the log-in page if necessary. The test should be a callable
|
|
||||||
that takes the user object and returns True if the user passes.
|
|
||||||
"""
|
|
||||||
def decorator(view_func):
|
|
||||||
def _wrapped_view(obj, request, *args, **kwargs):
|
|
||||||
if test_func(request.user):
|
|
||||||
return view_func(obj, request, *args, **kwargs)
|
|
||||||
json_content_type = 'application/json; charset=utf-8'
|
|
||||||
|
|
||||||
return HttpResponse(json.dumps('login required'), status=401,
|
|
||||||
content_type=json_content_type)
|
|
||||||
return wraps(view_func, assigned=available_attrs(view_func))(_wrapped_view)
|
|
||||||
return decorator
|
|
||||||
|
|
||||||
|
|
||||||
def api_login_required(function=None):
|
|
||||||
"""
|
|
||||||
Decorator for views that checks that the user is logged in, redirecting
|
|
||||||
to the log-in page if necessary.
|
|
||||||
"""
|
|
||||||
actual_decorator = api_user_passes_test(
|
|
||||||
lambda u: u.is_authenticated()
|
|
||||||
)
|
|
||||||
if function:
|
|
||||||
return actual_decorator(function)
|
|
||||||
return actual_decorator
|
|
||||||
|
|
||||||
|
|
||||||
def permission_required(perm, login_url=None):
|
def permission_required(perm, login_url=None):
|
||||||
"""
|
"""
|
||||||
Decorator for views that checks whether a user has a particular permission
|
Decorator for views that checks whether a user has a particular permission
|
||||||
|
Reference in New Issue
Block a user