mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-04 16:31:13 +00:00
use djangorestframwork in api
This commit is contained in:
16
api/urls.py
16
api/urls.py
@@ -4,12 +4,14 @@ from views import *
|
|||||||
|
|
||||||
|
|
||||||
urlpatterns = patterns('',
|
urlpatterns = patterns('',
|
||||||
url(r'^/$', list_repo),
|
url(r'^$', ReposView.as_view()),
|
||||||
url(r'^repo/list/$', list_repo),
|
url(r'^/$', ReposView.as_view()),
|
||||||
url(r'^repo/(?P<repo_id>[^/]+)/$', get_repo_info),
|
url(r'^repo/list/$', ReposView.as_view(), name='repos'),
|
||||||
url(r'^dir/(?P<repo_id>[^/]+)/root/$', get_repo_dir_path),
|
url(r'^repo/(?P<repo_id>[^/]+)/$', RepoView.as_view(), name='repo'),
|
||||||
url(r'^dir/(?P<repo_id>[^/]+)/$', get_repo_dir_path),
|
|
||||||
url(r'^dir/(?P<repo_id>[^/]+)/(?P<dir_id>[^/]+)/$', get_repo_dir_id),
|
url(r'^dir/(?P<repo_id>[^/]+)/root/$', RepoDirPathView.as_view()),
|
||||||
url(r'^file/(?P<repo_id>[^/]+)/(?P<file_id>[^/]+)/$', get_repo_file_id),
|
url(r'^dir/(?P<repo_id>[^/]+)/$', RepoDirPathView.as_view(), name='repo-dir-path'),
|
||||||
|
url(r'^dir/(?P<repo_id>[^/]+)/(?P<dir_id>[^/]+)/$', RepoDirIdView.as_view(), name='repo-dirr-id'),
|
||||||
|
url(r'^file/(?P<repo_id>[^/]+)/(?P<file_id>[^/]+)/$', RepoFileView.as_view(), name='repo-file'),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
296
api/views.py
296
api/views.py
@@ -6,7 +6,7 @@ import stat
|
|||||||
import simplejson as json
|
import simplejson as json
|
||||||
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseServerError
|
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseServerError
|
||||||
|
|
||||||
from auth.decorators import login_required
|
from auth.decorators import login_required, api_login_required
|
||||||
|
|
||||||
from seaserv import ccnet_rpc, ccnet_threaded_rpc, get_groups, get_users, get_repos, \
|
from seaserv import ccnet_rpc, ccnet_threaded_rpc, get_groups, get_users, get_repos, \
|
||||||
get_repo, get_commits, get_branches, \
|
get_repo, get_commits, get_branches, \
|
||||||
@@ -19,6 +19,15 @@ from seahub.utils import list_to_string, \
|
|||||||
check_filename_with_rename, get_accessible_repos, EMPTY_SHA1
|
check_filename_with_rename, get_accessible_repos, EMPTY_SHA1
|
||||||
|
|
||||||
from seahub.views import access_to_repo, validate_owner
|
from seahub.views import access_to_repo, validate_owner
|
||||||
|
from pysearpc import SearpcError
|
||||||
|
|
||||||
|
from djangorestframework.renderers import JSONRenderer
|
||||||
|
from djangorestframework.compat import View
|
||||||
|
from djangorestframework.mixins import ResponseMixin
|
||||||
|
from djangorestframework.response import Response
|
||||||
|
from django.core.urlresolvers import reverse
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
json_content_type = 'application/json; charset=utf-8'
|
json_content_type = 'application/json; charset=utf-8'
|
||||||
|
|
||||||
@@ -26,7 +35,7 @@ json_content_type = 'application/json; charset=utf-8'
|
|||||||
def api_error(request, code='404', msg=None):
|
def api_error(request, code='404', msg=None):
|
||||||
err_resp = {'error_msg':msg}
|
err_resp = {'error_msg':msg}
|
||||||
return HttpResponse(json.dumps(err_resp), status=code,
|
return HttpResponse(json.dumps(err_resp), status=code,
|
||||||
content_type=json_content_type)
|
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)
|
||||||
@@ -36,6 +45,7 @@ def can_access_repo(request, repo_id):
|
|||||||
# check whether user can view repo
|
# check whether user can view repo
|
||||||
return access_to_repo(request, repo_id, repo_ap)
|
return access_to_repo(request, repo_id, repo_ap)
|
||||||
|
|
||||||
|
|
||||||
def get_dir_entrys_by_path(reqquest, commit, path):
|
def get_dir_entrys_by_path(reqquest, commit, path):
|
||||||
dentrys = []
|
dentrys = []
|
||||||
if path[-1] != '/':
|
if path[-1] != '/':
|
||||||
@@ -43,8 +53,8 @@ def get_dir_entrys_by_path(reqquest, commit, path):
|
|||||||
|
|
||||||
if not commit.root_id == EMPTY_SHA1:
|
if not commit.root_id == EMPTY_SHA1:
|
||||||
try:
|
try:
|
||||||
dirs = seafserv_rpc.list_dir_by_path(commit.id,
|
dirs = seafserv_threaded_rpc.list_dir_by_path(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, "404", e.msg)
|
||||||
for dirent in dirs:
|
for dirent in dirs:
|
||||||
@@ -67,7 +77,7 @@ def get_dir_entrys_by_path(reqquest, commit, path):
|
|||||||
def get_dir_entrys_by_id(reqquest, dir_id):
|
def get_dir_entrys_by_id(reqquest, dir_id):
|
||||||
dentrys = []
|
dentrys = []
|
||||||
try:
|
try:
|
||||||
dirs = seafserv_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, "404", e.msg)
|
||||||
for dirent in dirs:
|
for dirent in dirs:
|
||||||
@@ -87,79 +97,85 @@ def get_dir_entrys_by_id(reqquest, dir_id):
|
|||||||
return HttpResponse(json.dumps(dentrys), status=200,
|
return HttpResponse(json.dumps(dentrys), status=200,
|
||||||
content_type=json_content_type)
|
content_type=json_content_type)
|
||||||
|
|
||||||
@login_required
|
class ReposView(ResponseMixin, View):
|
||||||
def list_repo(request):
|
renderers = (JSONRenderer,)
|
||||||
email = request.user.username
|
|
||||||
|
|
||||||
owned_repos = seafserv_threaded_rpc.list_owned_repos(email)
|
@api_login_required
|
||||||
calculate_repo_last_modify(owned_repos)
|
def get(self, request):
|
||||||
owned_repos.sort(lambda x, y: cmp(y.latest_modify, x.latest_modify))
|
email = request.user.username
|
||||||
|
|
||||||
n_repos = seafserv_threaded_rpc.list_share_repos(email,
|
owned_repos = seafserv_threaded_rpc.list_owned_repos(email)
|
||||||
'to_email', -1, -1)
|
calculate_repo_last_modify(owned_repos)
|
||||||
calculate_repo_last_modify(owned_repos)
|
owned_repos.sort(lambda x, y: cmp(y.latest_modify, x.latest_modify))
|
||||||
owned_repos.sort(lambda x, y: cmp(y.latest_modify, x.latest_modify))
|
|
||||||
|
|
||||||
repos_json = []
|
n_repos = seafserv_threaded_rpc.list_share_repos(email,
|
||||||
for r in owned_repos:
|
'to_email', -1, -1)
|
||||||
repo = {
|
calculate_repo_last_modify(owned_repos)
|
||||||
"id":r.props.id,
|
owned_repos.sort(lambda x, y: cmp(y.latest_modify, x.latest_modify))
|
||||||
"owner":"self",
|
|
||||||
"name":r.props.name,
|
|
||||||
"desc":r.props.desc,
|
|
||||||
"mtime":r.lastest_modify,
|
|
||||||
}
|
|
||||||
repos_json.append(repo)
|
|
||||||
|
|
||||||
for r in n_repos:
|
repos_json = []
|
||||||
repo = {
|
for r in owned_repos:
|
||||||
"id":r.props.id,
|
repo = {
|
||||||
"owner":r.props.shared_email,
|
"id":r.props.id,
|
||||||
"name":r.props.name,
|
"owner":"self",
|
||||||
"desc":r.props.desc,
|
"name":r.props.name,
|
||||||
"mtime":r.lastest_modify,
|
"desc":r.props.desc,
|
||||||
}
|
"mtime":r.lastest_modify,
|
||||||
repos_json.append(repo)
|
}
|
||||||
return HttpResponse(json.dumps(repos_json), status=200,
|
repos_json.append(repo)
|
||||||
content_type=json_content_type)
|
|
||||||
|
|
||||||
|
for r in n_repos:
|
||||||
|
repo = {
|
||||||
|
"id":r.props.id,
|
||||||
|
"owner":r.props.shared_email,
|
||||||
|
"name":r.props.name,
|
||||||
|
"desc":r.props.desc,
|
||||||
|
"mtime":r.lastest_modify,
|
||||||
|
}
|
||||||
|
repos_json.append(repo)
|
||||||
|
|
||||||
@login_required
|
response = Response(200, repos_json)
|
||||||
def get_repo_info(request, repo_id):
|
return self.render(response)
|
||||||
# check whether user can view repo
|
|
||||||
if not can_access_repo(request, repo_id):
|
|
||||||
return api_error(request, '403', "can not access repo")
|
|
||||||
|
|
||||||
# check whether use is repo owner
|
class RepoView(ResponseMixin, View):
|
||||||
if validate_owner(request, repo_id):
|
renderers = (JSONRenderer,)
|
||||||
owner = "self"
|
|
||||||
else:
|
|
||||||
owner = "share"
|
|
||||||
|
|
||||||
repo = get_repo(repo_id)
|
|
||||||
if not repo:
|
|
||||||
return api_error(request, '404', "repo not found")
|
|
||||||
|
|
||||||
try:
|
@api_login_required
|
||||||
repo.latest_modify = get_commits(repo.id, 0, 1)[0].ctime
|
def get_repo_info(request, repo_id):
|
||||||
except:
|
# check whether user can view repo
|
||||||
repo.latest_modify = None
|
if not can_access_repo(request, repo_id):
|
||||||
# query whether set password if repo is encrypted
|
return api_error(request, '403', "can not access repo")
|
||||||
|
|
||||||
|
# check whether use is repo owner
|
||||||
|
if validate_owner(request, repo_id):
|
||||||
|
owner = "self"
|
||||||
|
else:
|
||||||
|
owner = "share"
|
||||||
|
|
||||||
|
repo = get_repo(repo_id)
|
||||||
|
if not repo:
|
||||||
|
return api_error(request, '404', "repo not found")
|
||||||
|
|
||||||
password_set = False
|
|
||||||
if repo.props.encrypted:
|
|
||||||
try:
|
try:
|
||||||
ret = seafserv_rpc.is_passwd_set(repo_id, request.user.username)
|
repo.latest_modify = get_commits(repo.id, 0, 1)[0].ctime
|
||||||
if ret == 1:
|
except:
|
||||||
password_set = True
|
repo.latest_modify = None
|
||||||
except SearpcError, e:
|
|
||||||
return api_error(request, '403', e.msg)
|
|
||||||
|
|
||||||
# query repo infomation
|
# query whether set password if repo is encrypted
|
||||||
repo_size = seafserv_threaded_rpc.server_repo_size(repo_id)
|
password_set = False
|
||||||
current_commit = get_commits(repo_id, 0, 1)[0]
|
if repo.props.encrypted:
|
||||||
|
try:
|
||||||
|
ret = seafserv_rpc.is_passwd_set(repo_id, request.user.username)
|
||||||
|
if ret == 1:
|
||||||
|
password_set = True
|
||||||
|
except SearpcError, e:
|
||||||
|
return api_error(request, '403', e.msg)
|
||||||
|
|
||||||
repo_json = {
|
# query repo infomation
|
||||||
|
repo_size = seafserv_threaded_rpc.server_repo_size(repo_id)
|
||||||
|
current_commit = get_commits(repo_id, 0, 1)[0]
|
||||||
|
|
||||||
|
repo_json = {
|
||||||
"id":repo.props.id,
|
"id":repo.props.id,
|
||||||
"owner":owner,
|
"owner":owner,
|
||||||
"name":repo.props.name,
|
"name":repo.props.name,
|
||||||
@@ -169,90 +185,104 @@ def get_repo_info(request, repo_id):
|
|||||||
"size":repo_size,
|
"size":repo_size,
|
||||||
"commit":current_commit.id,
|
"commit":current_commit.id,
|
||||||
}
|
}
|
||||||
|
|
||||||
return HttpResponse(json.dumps(repo_json), status=200,
|
response = Response(200, repo_json)
|
||||||
content_type=json_content_type)
|
return self.render(response)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
class RepoDirPathView(ResponseMixin, View):
|
||||||
def get_repo_dir_path(request, repo_id):
|
renderers = (JSONRenderer,)
|
||||||
if not can_access_repo(request, repo_id):
|
|
||||||
return api_error(request, '403', "can not access repo")
|
|
||||||
current_commit = get_commits(repo_id, 0, 1)[0]
|
|
||||||
|
|
||||||
repo = get_repo(repo_id)
|
@api_login_required
|
||||||
if not repo:
|
def get(self, request, repo_id):
|
||||||
return api_error(request, '404', "repo not found")
|
if not can_access_repo(request, repo_id):
|
||||||
|
return api_error(request, '403', "can not access repo")
|
||||||
|
current_commit = get_commits(repo_id, 0, 1)[0]
|
||||||
|
|
||||||
password_set = False
|
repo = get_repo(repo_id)
|
||||||
if repo.props.encrypted:
|
if not repo:
|
||||||
try:
|
return api_error(request, '404', "repo not found")
|
||||||
ret = seafserv_rpc.is_passwd_set(repo_id, request.user.username)
|
|
||||||
if ret == 1:
|
|
||||||
password_set = True
|
|
||||||
except SearpcError, e:
|
|
||||||
return api_error(request, '403', e.msg)
|
|
||||||
if repo.props.encrypted and not password_set:
|
|
||||||
return api_error(request, '403', "password needed")
|
|
||||||
|
|
||||||
path = request.GET.get('p', '/')
|
password_set = False
|
||||||
return get_dir_entrys_by_path(request, current_commit, path)
|
if repo.props.encrypted:
|
||||||
|
try:
|
||||||
|
ret = seafserv_rpc.is_passwd_set(repo_id, request.user.username)
|
||||||
|
if ret == 1:
|
||||||
|
password_set = True
|
||||||
|
except SearpcError, e:
|
||||||
|
return api_error(request, '403', e.msg)
|
||||||
|
|
||||||
|
if repo.props.encrypted and not password_set:
|
||||||
|
return api_error(request, '403', "password needed")
|
||||||
|
|
||||||
|
path = request.GET.get('p', '/')
|
||||||
|
return get_dir_entrys_by_path(request, current_commit, path)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
|
||||||
def get_repo_dir_id(request, repo_id, dir_id):
|
|
||||||
if not can_access_repo(request, repo_id):
|
|
||||||
return api_error(request, '403', "can not access repo")
|
|
||||||
|
|
||||||
repo = get_repo(repo_id)
|
class RepoDirIdView(ResponseMixin, View):
|
||||||
if not repo:
|
renderers = (JSONRenderer,)
|
||||||
return api_error(request, '404', "repo not found")
|
|
||||||
|
|
||||||
password_set = False
|
@api_login_required
|
||||||
if repo.props.encrypted:
|
def get(self, request, repo_id, dir_id):
|
||||||
try:
|
if not can_access_repo(request, repo_id):
|
||||||
ret = seafserv_rpc.is_passwd_set(repo_id, request.user.username)
|
return api_error(request, '403', "can not access repo")
|
||||||
if ret == 1:
|
|
||||||
password_set = True
|
|
||||||
except SearpcError, e:
|
|
||||||
return api_error(request, '403', e.msg)
|
|
||||||
|
|
||||||
if repo.props.encrypted and not password_set:
|
repo = get_repo(repo_id)
|
||||||
return api_error(request, '403', "password needed")
|
if not repo:
|
||||||
|
return api_error(request, '404', "repo not found")
|
||||||
|
|
||||||
return get_dir_entrys_by_id(request, dir_id)
|
password_set = False
|
||||||
|
if repo.props.encrypted:
|
||||||
|
try:
|
||||||
|
ret = seafserv_rpc.is_passwd_set(repo_id, request.user.username)
|
||||||
|
if ret == 1:
|
||||||
|
password_set = True
|
||||||
|
except SearpcError, e:
|
||||||
|
return api_error(request, '403', e.msg)
|
||||||
|
|
||||||
@login_required
|
if repo.props.encrypted and not password_set:
|
||||||
def get_repo_file_id(request, repo_id, file_id):
|
return api_error(request, '403', "password needed")
|
||||||
if not can_access_repo(request, repo_id):
|
|
||||||
return api_error(request, '403', "can not access repo")
|
|
||||||
|
|
||||||
repo = get_repo(repo_id)
|
return get_dir_entrys_by_id(request, dir_id)
|
||||||
if not repo:
|
|
||||||
return api_error(request, '404', "repo not found")
|
|
||||||
|
|
||||||
password_set = False
|
|
||||||
if repo.props.encrypted:
|
|
||||||
try:
|
|
||||||
ret = seafserv_rpc.is_passwd_set(repo_id, request.user.username)
|
|
||||||
if ret == 1:
|
|
||||||
password_set = True
|
|
||||||
except SearpcError, e:
|
|
||||||
return api_error(request, '403', e.msg)
|
|
||||||
|
|
||||||
if repo.props.encrypted and not password_set:
|
class RepoFileView(ResponseMixin, View):
|
||||||
return api_error(request, '403', "password needed")
|
renderers = (JSONRenderer,)
|
||||||
file_name = request.GET.get('file_name', file_id)
|
|
||||||
token = gen_token()
|
|
||||||
# put token into memory in seaf-server
|
|
||||||
seafserv_rpc.web_save_access_token(token, file_id)
|
|
||||||
|
|
||||||
http_server_root = get_httpserver_root()
|
@api_login_required
|
||||||
op='download'
|
def get(self, request, repo_id, file_id):
|
||||||
redirect_url = '%s/access?repo_id=%s&id=%s&filename=%s&op=%s&t=%s&u=%s' % (http_server_root,
|
if not can_access_repo(request, repo_id):
|
||||||
|
return api_error(request, '403', "can not access repo")
|
||||||
|
|
||||||
|
repo = get_repo(repo_id)
|
||||||
|
if not repo:
|
||||||
|
return api_error(request, '404', "repo not found")
|
||||||
|
|
||||||
|
password_set = False
|
||||||
|
if repo.props.encrypted:
|
||||||
|
try:
|
||||||
|
ret = seafserv_rpc.is_passwd_set(repo_id, request.user.username)
|
||||||
|
if ret == 1:
|
||||||
|
password_set = True
|
||||||
|
except SearpcError, e:
|
||||||
|
return api_error(request, '403', e.msg)
|
||||||
|
|
||||||
|
if repo.props.encrypted and not password_set:
|
||||||
|
return api_error(request, '403', "password needed")
|
||||||
|
file_name = request.GET.get('file_name', file_id)
|
||||||
|
token = gen_token()
|
||||||
|
# put token into memory in seaf-server
|
||||||
|
seafserv_rpc.web_save_access_token(token, file_id)
|
||||||
|
|
||||||
|
http_server_root = get_httpserver_root()
|
||||||
|
op='download'
|
||||||
|
redirect_url = '%s/access?repo_id=%s&id=%s&filename=%s&op=%s&t=%s&u=%s' % (http_server_root,
|
||||||
repo_id, file_id,
|
repo_id, file_id,
|
||||||
file_name, op,
|
file_name, op,
|
||||||
token,
|
token,
|
||||||
request.user.username)
|
request.user.username)
|
||||||
|
|
||||||
return HttpResponseRedirect(redirect_url)
|
return HttpResponseRedirect(redirect_url)
|
||||||
|
|
||||||
|
|
||||||
|
@@ -44,6 +44,44 @@ def login_required(function=None, redirect_field_name=REDIRECT_FIELD_NAME):
|
|||||||
return actual_decorator
|
return actual_decorator
|
||||||
|
|
||||||
|
|
||||||
|
def api_user_passes_test(test_func, login_url=None, redirect_field_name=REDIRECT_FIELD_NAME):
|
||||||
|
"""
|
||||||
|
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.
|
||||||
|
"""
|
||||||
|
if not login_url:
|
||||||
|
from django.conf import settings
|
||||||
|
login_url = settings.LOGIN_URL
|
||||||
|
|
||||||
|
def decorator(view_func):
|
||||||
|
def _wrapped_view(obj, request, *args, **kwargs):
|
||||||
|
if test_func(request.user):
|
||||||
|
return view_func(obj, request, *args, **kwargs)
|
||||||
|
path = urlquote(request.get_full_path())
|
||||||
|
tup = login_url, redirect_field_name, path
|
||||||
|
json_content_type = 'application/json; charset=utf-8'
|
||||||
|
|
||||||
|
return HttpResponse(json.dumps('%s?%s=%s' % tup), 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, redirect_field_name=REDIRECT_FIELD_NAME):
|
||||||
|
"""
|
||||||
|
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(),
|
||||||
|
redirect_field_name=redirect_field_name
|
||||||
|
)
|
||||||
|
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
|
||||||
|
1
urls.py
1
urls.py
@@ -43,7 +43,6 @@ urlpatterns = patterns('',
|
|||||||
|
|
||||||
(r'^share/', include('share.urls')),
|
(r'^share/', include('share.urls')),
|
||||||
(r'^api/', include('api.urls')),
|
(r'^api/', include('api.urls')),
|
||||||
(r'^rest/', include('djangorestframework.urls')),
|
|
||||||
url(r'^shareadmin/$', share_admin, name='share_admin'),
|
url(r'^shareadmin/$', share_admin, name='share_admin'),
|
||||||
(r'^shareadmin/removeshare/$', repo_remove_share),
|
(r'^shareadmin/removeshare/$', repo_remove_share),
|
||||||
(r'^sharedlink/get/$', get_shared_link),
|
(r'^sharedlink/get/$', get_shared_link),
|
||||||
|
Reference in New Issue
Block a user