1
0
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:
poetwang
2012-09-01 13:35:21 +08:00
parent d7a570dc91
commit a09bae86e6
4 changed files with 113 additions and 79 deletions

View File

@@ -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

View File

@@ -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'),

View File

@@ -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')

View File

@@ -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