2012-12-14 12:53:36 +00:00
|
|
|
# encoding: utf-8
|
|
|
|
import os
|
|
|
|
import stat
|
2012-12-16 14:34:52 +00:00
|
|
|
import simplejson as json
|
2012-12-14 12:53:36 +00:00
|
|
|
from urllib2 import unquote, quote
|
|
|
|
import seahub.settings as settings
|
|
|
|
|
|
|
|
from rest_framework import parsers
|
|
|
|
from rest_framework import status
|
|
|
|
from rest_framework import renderers
|
|
|
|
from rest_framework.permissions import IsAuthenticated
|
2012-12-26 03:03:38 +00:00
|
|
|
from rest_framework.reverse import reverse
|
2012-12-14 12:53:36 +00:00
|
|
|
from rest_framework.response import Response
|
2012-12-26 03:03:38 +00:00
|
|
|
from rest_framework.throttling import AnonRateThrottle, UserRateThrottle
|
2012-12-14 12:53:36 +00:00
|
|
|
from rest_framework.views import APIView
|
|
|
|
from django.contrib.sites.models import RequestSite
|
2012-12-16 14:34:52 +00:00
|
|
|
from django.http import HttpResponse
|
2012-12-14 12:53:36 +00:00
|
|
|
|
|
|
|
from models import Token
|
|
|
|
from authentication import TokenAuthentication
|
2013-02-20 12:51:37 +00:00
|
|
|
from permissions import IsRepoWritable, IsRepoAccessible, IsRepoOwner
|
2012-12-14 12:53:36 +00:00
|
|
|
from serializers import AuthTokenSerializer
|
|
|
|
from base.accounts import User
|
|
|
|
from share.models import FileShare
|
|
|
|
from seahub.views import access_to_repo, validate_owner
|
|
|
|
from seahub.utils import gen_file_get_url, gen_token, gen_file_upload_url, \
|
2012-12-15 06:53:15 +00:00
|
|
|
check_filename_with_rename, get_starred_files, get_ccnetapplet_root, \
|
2012-12-23 14:27:16 +00:00
|
|
|
get_ccnet_server_addr_port, star_file, unstar_file, string2list
|
2013-02-20 12:51:37 +00:00
|
|
|
try:
|
|
|
|
from seahub.settings import CLOUD_MODE
|
|
|
|
except ImportError:
|
|
|
|
CLOUD_MODE = False
|
2012-12-14 12:53:36 +00:00
|
|
|
|
2013-02-20 12:51:37 +00:00
|
|
|
from pysearpc import SearpcError, SearpcObjEncoder
|
2012-12-19 02:58:14 +00:00
|
|
|
from seaserv import seafserv_rpc, seafserv_threaded_rpc, server_repo_size, \
|
2012-12-15 06:53:15 +00:00
|
|
|
get_personal_groups_by_user, get_session_info, get_repo_token_nonnull, \
|
2012-12-19 02:58:14 +00:00
|
|
|
get_group_repos, get_repo, check_permission, get_commits, is_passwd_set,\
|
2013-02-20 12:51:37 +00:00
|
|
|
list_personal_repos_by_owner, list_personal_shared_repos, check_quota, \
|
|
|
|
list_share_repos, get_group_repos_by_owner, list_inner_pub_repos_by_owner,\
|
2013-03-02 08:58:37 +00:00
|
|
|
remove_share, unshare_group_repo, unset_inner_pub_repo, get_user_quota, \
|
|
|
|
get_user_share_usage, get_user_quota_usage, CALC_SHARE_USAGE
|
2012-12-14 12:53:36 +00:00
|
|
|
|
2012-12-16 14:34:52 +00:00
|
|
|
json_content_type = 'application/json; charset=utf-8'
|
|
|
|
|
2012-12-23 14:27:16 +00:00
|
|
|
# Define custom HTTP status code. 4xx starts from 440, 5xx starts from 520.
|
|
|
|
HTTP_440_REPO_PASSWD_REQUIRED = 440
|
|
|
|
HTTP_520_OPERATION_FAILED = 520
|
|
|
|
|
2012-12-14 12:53:36 +00:00
|
|
|
class Ping(APIView):
|
|
|
|
"""
|
|
|
|
Returns a simple `pong` message when client calls `api2/ping/`.
|
|
|
|
For example:
|
|
|
|
curl http://127.0.0.1:8000/api2/ping/
|
|
|
|
"""
|
|
|
|
def get(self, request, format=None):
|
|
|
|
return Response('pong')
|
|
|
|
|
2012-12-15 06:53:15 +00:00
|
|
|
def head(self, request, format=None):
|
|
|
|
return Response(headers={'foo': 'bar',})
|
|
|
|
|
2012-12-14 12:53:36 +00:00
|
|
|
class AuthPing(APIView):
|
|
|
|
"""
|
|
|
|
Returns a simple `pong` message when client provided an auth token.
|
|
|
|
For example:
|
|
|
|
curl -H "Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b" http://127.0.0.1:8000/api2/auth/ping/
|
|
|
|
"""
|
|
|
|
authentication_classes = (TokenAuthentication, )
|
|
|
|
permission_classes = (IsAuthenticated,)
|
|
|
|
|
|
|
|
def get(self, request, format=None):
|
|
|
|
return Response('pong')
|
|
|
|
|
|
|
|
class ObtainAuthToken(APIView):
|
|
|
|
"""
|
|
|
|
Returns auth token if username and password are valid.
|
|
|
|
For example:
|
2012-12-29 02:31:23 +00:00
|
|
|
curl -d "username=foo@example.com&password=123456" http://127.0.0.1:8000/api2/auth-token/
|
2012-12-14 12:53:36 +00:00
|
|
|
"""
|
2012-12-26 03:03:38 +00:00
|
|
|
throttle_classes = (AnonRateThrottle, )
|
2012-12-14 12:53:36 +00:00
|
|
|
permission_classes = ()
|
|
|
|
parser_classes = (parsers.FormParser, parsers.MultiPartParser, parsers.JSONParser,)
|
|
|
|
renderer_classes = (renderers.JSONRenderer,)
|
|
|
|
model = Token
|
|
|
|
|
|
|
|
def post(self, request):
|
|
|
|
serializer = AuthTokenSerializer(data=request.DATA)
|
|
|
|
if serializer.is_valid():
|
|
|
|
token, created = Token.objects.get_or_create(user=serializer.object['user'].username)
|
|
|
|
return Response({'token': token.key})
|
|
|
|
|
|
|
|
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
|
2012-12-23 14:27:16 +00:00
|
|
|
def api_error(code, msg):
|
|
|
|
err_resp = {'error_msg': msg}
|
2012-12-14 12:53:36 +00:00
|
|
|
return Response(err_resp, status=code)
|
|
|
|
|
|
|
|
class Account(APIView):
|
|
|
|
"""
|
|
|
|
Show account info.
|
|
|
|
"""
|
|
|
|
authentication_classes = (TokenAuthentication, )
|
|
|
|
permission_classes = (IsAuthenticated,)
|
2012-12-26 03:03:38 +00:00
|
|
|
throttle_classes = (UserRateThrottle, )
|
2012-12-14 12:53:36 +00:00
|
|
|
|
|
|
|
def get(self, request, format=None):
|
|
|
|
info = {}
|
|
|
|
email = request.user.username
|
|
|
|
info['email'] = email
|
2013-03-02 08:58:37 +00:00
|
|
|
info['total'] = get_user_quota(email)
|
|
|
|
|
|
|
|
if CALC_SHARE_USAGE:
|
|
|
|
my_usage = get_user_quota_usage(email)
|
|
|
|
share_usage = get_user_share_usage(email)
|
|
|
|
info['usage'] = my_usage + share_usage
|
|
|
|
else:
|
|
|
|
info['usage'] = get_user_quota_usage(email)
|
|
|
|
|
2012-12-14 12:53:36 +00:00
|
|
|
return Response(info)
|
|
|
|
|
|
|
|
def calculate_repo_info(repo_list, username):
|
|
|
|
"""
|
|
|
|
Get some info for repo.
|
|
|
|
|
|
|
|
"""
|
|
|
|
for repo in repo_list:
|
2012-12-19 02:58:14 +00:00
|
|
|
commit = get_commits(repo.id, 0, 1)[0]
|
|
|
|
if not commit:
|
|
|
|
continue
|
|
|
|
repo.latest_modify = commit.ctime
|
|
|
|
repo.root = commit.root_id
|
|
|
|
repo.size = server_repo_size(repo.id)
|
2012-12-14 12:53:36 +00:00
|
|
|
|
|
|
|
class Repos(APIView):
|
|
|
|
authentication_classes = (TokenAuthentication, )
|
|
|
|
permission_classes = (IsAuthenticated,)
|
2012-12-26 03:03:38 +00:00
|
|
|
throttle_classes = (UserRateThrottle, )
|
2012-12-14 12:53:36 +00:00
|
|
|
|
|
|
|
def get(self, request, format=None):
|
|
|
|
email = request.user.username
|
2012-12-19 02:58:14 +00:00
|
|
|
repos_json = []
|
2012-12-14 12:53:36 +00:00
|
|
|
|
2012-12-19 02:58:14 +00:00
|
|
|
owned_repos = list_personal_repos_by_owner(email)
|
|
|
|
calculate_repo_info(owned_repos, email)
|
2012-12-14 12:53:36 +00:00
|
|
|
owned_repos.sort(lambda x, y: cmp(y.latest_modify, x.latest_modify))
|
|
|
|
for r in owned_repos:
|
|
|
|
repo = {
|
|
|
|
"type":"repo",
|
|
|
|
"id":r.id,
|
|
|
|
"owner":email,
|
|
|
|
"name":r.name,
|
|
|
|
"desc":r.desc,
|
|
|
|
"mtime":r.latest_modify,
|
|
|
|
"root":r.root,
|
|
|
|
"size":r.size,
|
|
|
|
"encrypted":r.encrypted,
|
2012-12-19 13:36:57 +00:00
|
|
|
"permission": 'rw', # Always have read-write permission to owned repo
|
2012-12-14 12:53:36 +00:00
|
|
|
}
|
|
|
|
repos_json.append(repo)
|
2012-12-19 02:58:14 +00:00
|
|
|
|
|
|
|
shared_repos = list_personal_shared_repos(email, 'to_email', -1, -1)
|
|
|
|
for r in shared_repos:
|
|
|
|
commit = get_commits(r.repo_id, 0, 1)[0]
|
|
|
|
if not commit:
|
|
|
|
continue
|
|
|
|
r.latest_modify = commit.ctime
|
|
|
|
r.root = commit.root_id
|
|
|
|
r.size = server_repo_size(r.repo_id)
|
|
|
|
r.password_need = is_passwd_set(r.repo_id, email)
|
2012-12-19 13:36:57 +00:00
|
|
|
r.permission = check_permission(r.repo_id, email)
|
2012-12-14 12:53:36 +00:00
|
|
|
repo = {
|
|
|
|
"type":"srepo",
|
2012-12-19 02:58:14 +00:00
|
|
|
"id":r.repo_id,
|
|
|
|
"owner":r.user,
|
|
|
|
"name":r.repo_name,
|
|
|
|
"desc":r.repo_desc,
|
2012-12-14 12:53:36 +00:00
|
|
|
"mtime":r.latest_modify,
|
|
|
|
"root":r.root,
|
|
|
|
"size":r.size,
|
|
|
|
"encrypted":r.encrypted,
|
2012-12-19 13:36:57 +00:00
|
|
|
"permission": r.permission,
|
2012-12-14 12:53:36 +00:00
|
|
|
}
|
|
|
|
repos_json.append(repo)
|
|
|
|
|
|
|
|
groups = get_personal_groups_by_user(email)
|
|
|
|
for group in groups:
|
|
|
|
g_repos = get_group_repos(group.id, email)
|
|
|
|
calculate_repo_info (g_repos, email)
|
2012-12-19 02:58:14 +00:00
|
|
|
g_repos.sort(lambda x, y: cmp(y.latest_modify, x.latest_modify))
|
2012-12-14 12:53:36 +00:00
|
|
|
for r in g_repos:
|
|
|
|
repo = {
|
|
|
|
"type":"grepo",
|
|
|
|
"id":r.id,
|
|
|
|
"owner":group.group_name,
|
|
|
|
"name":r.name,
|
|
|
|
"desc":r.desc,
|
|
|
|
"mtime":r.latest_modify,
|
|
|
|
"root":r.root,
|
|
|
|
"size":r.size,
|
|
|
|
"encrypted":r.encrypted,
|
2012-12-19 13:36:57 +00:00
|
|
|
"permission": check_permission(r.id, email),
|
2012-12-14 12:53:36 +00:00
|
|
|
}
|
|
|
|
repos_json.append(repo)
|
|
|
|
|
|
|
|
return Response(repos_json)
|
|
|
|
|
|
|
|
def can_access_repo(request, repo_id):
|
|
|
|
if not check_permission(repo_id, request.user.username):
|
|
|
|
return False
|
|
|
|
return True
|
2012-12-23 14:27:16 +00:00
|
|
|
|
2012-12-25 14:30:18 +00:00
|
|
|
def set_repo_password(request, repo, password):
|
|
|
|
assert password, 'password must not be none'
|
|
|
|
|
|
|
|
try:
|
|
|
|
seafserv_threaded_rpc.set_passwd(repo.id, request.user.username, password)
|
|
|
|
except SearpcError, e:
|
|
|
|
if e.msg == 'Bad arguments':
|
2012-12-26 02:26:41 +00:00
|
|
|
return api_error(status.HTTP_400_BAD_REQUEST, e.msg)
|
2012-12-25 14:30:18 +00:00
|
|
|
elif e.msg == 'Repo is not encrypted':
|
2012-12-26 02:26:41 +00:00
|
|
|
return api_error(status.HTTP_409_CONFLICT, e.msg)
|
2012-12-25 14:30:18 +00:00
|
|
|
elif e.msg == 'Incorrect password':
|
2012-12-26 02:26:41 +00:00
|
|
|
return api_error(status.HTTP_400_BAD_REQUEST, e.msg)
|
2012-12-25 14:30:18 +00:00
|
|
|
elif e.msg == 'Internal server error':
|
2012-12-26 02:26:41 +00:00
|
|
|
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, e.msg)
|
2012-12-25 14:30:18 +00:00
|
|
|
else:
|
2012-12-26 02:26:41 +00:00
|
|
|
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, e.msg)
|
2012-12-25 14:30:18 +00:00
|
|
|
|
2012-12-23 14:27:16 +00:00
|
|
|
def check_repo_access_permission(request, repo):
|
|
|
|
if not can_access_repo(request, repo.id):
|
|
|
|
return api_error(status.HTTP_403_FORBIDDEN, 'Forbid to access this repo.')
|
|
|
|
|
|
|
|
password_set = False
|
|
|
|
if repo.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(status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
|
|
"SearpcError:" + e.msg)
|
|
|
|
|
|
|
|
if not password_set:
|
|
|
|
password = request.REQUEST.get('password', default=None)
|
|
|
|
if not password:
|
|
|
|
return api_error(HTTP_440_REPO_PASSWD_REQUIRED,
|
|
|
|
'Repo password is needed.')
|
|
|
|
|
|
|
|
return set_repo_password(request, repo, password)
|
|
|
|
|
2012-12-14 12:53:36 +00:00
|
|
|
class Repo(APIView):
|
|
|
|
authentication_classes = (TokenAuthentication, )
|
2012-12-25 03:09:34 +00:00
|
|
|
permission_classes = (IsAuthenticated, IsRepoAccessible, )
|
2012-12-26 03:03:38 +00:00
|
|
|
throttle_classes = (UserRateThrottle, )
|
2012-12-15 06:53:15 +00:00
|
|
|
|
2012-12-14 12:53:36 +00:00
|
|
|
def get(self, request, repo_id, format=None):
|
|
|
|
repo = get_repo(repo_id)
|
|
|
|
if not repo:
|
2012-12-23 14:27:16 +00:00
|
|
|
return api_error(status.HTTP_404_NOT_FOUND, 'Repo not found.')
|
2012-12-14 12:53:36 +00:00
|
|
|
|
2012-12-25 03:09:34 +00:00
|
|
|
# check whether user is repo owner
|
2012-12-14 12:53:36 +00:00
|
|
|
if validate_owner(request, repo_id):
|
|
|
|
owner = "self"
|
|
|
|
else:
|
|
|
|
owner = "share"
|
|
|
|
|
2012-12-23 14:27:16 +00:00
|
|
|
last_commit = get_commits(repo.id, 0, 1)[0]
|
2012-12-19 02:58:14 +00:00
|
|
|
repo.latest_modify = last_commit.ctime if last_commit else None
|
2012-12-14 12:53:36 +00:00
|
|
|
|
|
|
|
# query repo infomation
|
|
|
|
repo.size = seafserv_threaded_rpc.server_repo_size(repo_id)
|
|
|
|
current_commit = get_commits(repo_id, 0, 1)[0]
|
2012-12-19 02:58:14 +00:00
|
|
|
root_id = current_commit.root_id if current_commit else None
|
2012-12-15 06:53:15 +00:00
|
|
|
|
2012-12-14 12:53:36 +00:00
|
|
|
repo_json = {
|
|
|
|
"type":"repo",
|
|
|
|
"id":repo.id,
|
|
|
|
"owner":owner,
|
|
|
|
"name":repo.name,
|
|
|
|
"desc":repo.desc,
|
2012-12-24 08:53:32 +00:00
|
|
|
"mtime":repo.latest_modify,
|
2012-12-14 12:53:36 +00:00
|
|
|
"size":repo.size,
|
|
|
|
"encrypted":repo.encrypted,
|
2012-12-19 02:58:14 +00:00
|
|
|
"root":root_id,
|
2012-12-14 12:53:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return Response(repo_json)
|
|
|
|
|
|
|
|
def post(self, request, repo_id, format=None):
|
2012-12-25 03:09:34 +00:00
|
|
|
repo = get_repo(repo_id)
|
|
|
|
if not repo:
|
|
|
|
return api_error(status.HTTP_404_NOT_FOUND, 'Repo not found.')
|
|
|
|
|
|
|
|
resp = check_repo_access_permission(request, repo)
|
2012-12-14 12:53:36 +00:00
|
|
|
if resp:
|
|
|
|
return resp
|
|
|
|
op = request.GET.get('op', 'setpassword')
|
|
|
|
if op == 'setpassword':
|
|
|
|
return Response("success")
|
|
|
|
|
|
|
|
return Response("unsupported operation")
|
|
|
|
|
2012-12-23 14:27:16 +00:00
|
|
|
class DownloadRepo(APIView):
|
|
|
|
authentication_classes = (TokenAuthentication, )
|
2012-12-25 03:09:34 +00:00
|
|
|
permission_classes = (IsAuthenticated, IsRepoAccessible, )
|
2012-12-26 03:03:38 +00:00
|
|
|
throttle_classes = (UserRateThrottle, )
|
2012-12-14 12:53:36 +00:00
|
|
|
|
2012-12-23 14:27:16 +00:00
|
|
|
def get(self, request, repo_id, format=None):
|
|
|
|
repo = get_repo(repo_id)
|
|
|
|
if not repo:
|
|
|
|
return api_error(status.HTTP_404_NOT_FOUND, 'Repo not found.')
|
2012-12-14 12:53:36 +00:00
|
|
|
|
2012-12-23 14:27:16 +00:00
|
|
|
# generate download url for client
|
|
|
|
ccnet_applet_root = get_ccnetapplet_root()
|
|
|
|
relay_id = get_session_info().id
|
|
|
|
addr, port = get_ccnet_server_addr_port ()
|
2012-12-25 03:09:34 +00:00
|
|
|
email = request.user.username
|
2012-12-23 14:27:16 +00:00
|
|
|
token = get_repo_token_nonnull(repo_id, request.user.username)
|
2012-12-25 03:09:34 +00:00
|
|
|
repo_name = repo.name
|
2012-12-23 14:27:16 +00:00
|
|
|
enc = 1 if repo.encrypted else ''
|
2013-02-20 02:16:35 +00:00
|
|
|
magic = repo.magic if repo.encrypted else ''
|
2012-12-14 12:53:36 +00:00
|
|
|
|
2012-12-23 14:27:16 +00:00
|
|
|
info_json = {
|
|
|
|
'relay_id': relay_id,
|
|
|
|
'relay_addr': addr,
|
|
|
|
'relay_port': port,
|
|
|
|
'email': email,
|
|
|
|
'token': token,
|
|
|
|
'repo_id': repo_id,
|
2012-12-25 03:09:34 +00:00
|
|
|
'repo_name': repo_name,
|
2012-12-23 14:27:16 +00:00
|
|
|
'encrypted': enc,
|
2013-02-20 02:16:35 +00:00
|
|
|
'magic': magic,
|
2012-12-23 14:27:16 +00:00
|
|
|
}
|
|
|
|
return Response(info_json)
|
2012-12-25 03:09:34 +00:00
|
|
|
|
|
|
|
class UploadLinkView(APIView):
|
|
|
|
authentication_classes = (TokenAuthentication, )
|
|
|
|
permission_classes = (IsAuthenticated, )
|
2012-12-26 03:03:38 +00:00
|
|
|
throttle_classes = (UserRateThrottle, )
|
2012-12-25 03:09:34 +00:00
|
|
|
|
|
|
|
def get(self, request, repo_id, format=None):
|
|
|
|
repo = get_repo(repo_id)
|
|
|
|
if check_permission(repo_id, request.user.username) == 'rw':
|
|
|
|
token = seafserv_rpc.web_get_access_token(repo_id,
|
|
|
|
'dummy',
|
|
|
|
'upload',
|
|
|
|
request.user.username)
|
|
|
|
else:
|
|
|
|
return api_error(status.HTTP_403_FORBIDDEN, "Can not access repo")
|
|
|
|
|
2013-01-08 08:35:34 +00:00
|
|
|
if check_quota(repo_id) < 0:
|
2013-03-02 08:58:37 +00:00
|
|
|
return api_error(HTTP_520_OPERATION_FAILED, 'Above quota')
|
2012-12-25 03:09:34 +00:00
|
|
|
|
2013-01-05 03:54:15 +00:00
|
|
|
upload_url = gen_file_upload_url(token, 'upload-api')
|
2012-12-25 03:09:34 +00:00
|
|
|
return Response(upload_url)
|
2012-12-23 14:27:16 +00:00
|
|
|
|
2012-12-14 12:53:36 +00:00
|
|
|
def get_file_size (id):
|
|
|
|
size = seafserv_threaded_rpc.get_file_size(id)
|
|
|
|
return size if size else 0
|
|
|
|
|
|
|
|
def get_dir_entrys_by_id(request, dir_id):
|
|
|
|
try:
|
|
|
|
dirs = seafserv_threaded_rpc.list_dir(dir_id)
|
|
|
|
except SearpcError, e:
|
2012-12-23 14:27:16 +00:00
|
|
|
return api_error(HTTP_520_OPERATION_FAILED,
|
|
|
|
"Failed to list dir.")
|
2012-12-14 12:53:36 +00:00
|
|
|
|
2012-12-26 08:29:53 +00:00
|
|
|
dir_list, file_list = [], []
|
2012-12-14 12:53:36 +00:00
|
|
|
for dirent in dirs:
|
|
|
|
dtype = "file"
|
|
|
|
entry={}
|
|
|
|
if stat.S_ISDIR(dirent.mode):
|
|
|
|
dtype = "dir"
|
|
|
|
else:
|
|
|
|
try:
|
|
|
|
entry["size"] = get_file_size(dirent.obj_id)
|
|
|
|
except Exception, e:
|
|
|
|
entry["size"]=0
|
|
|
|
|
|
|
|
entry["type"]=dtype
|
|
|
|
entry["name"]=dirent.obj_name
|
|
|
|
entry["id"]=dirent.obj_id
|
2012-12-26 08:29:53 +00:00
|
|
|
if dtype == 'dir':
|
|
|
|
dir_list.append(entry)
|
|
|
|
else:
|
|
|
|
file_list.append(entry)
|
|
|
|
|
|
|
|
dir_list.sort(lambda x, y : cmp(x['name'].lower(),y['name'].lower()))
|
|
|
|
file_list.sort(lambda x, y : cmp(x['name'].lower(),y['name'].lower()))
|
|
|
|
dentrys = dir_list + file_list
|
|
|
|
|
2012-12-16 14:34:52 +00:00
|
|
|
response = HttpResponse(json.dumps(dentrys), status=200,
|
|
|
|
content_type=json_content_type)
|
|
|
|
response["oid"] = dir_id
|
|
|
|
return response
|
2012-12-14 12:53:36 +00:00
|
|
|
|
|
|
|
def get_shared_link(request, repo_id, path):
|
|
|
|
l = FileShare.objects.filter(repo_id=repo_id).filter(\
|
|
|
|
username=request.user.username).filter(path=path)
|
|
|
|
token = None
|
|
|
|
if len(l) > 0:
|
|
|
|
fileshare = l[0]
|
|
|
|
token = fileshare.token
|
|
|
|
else:
|
|
|
|
token = gen_token(max_length=10)
|
|
|
|
|
|
|
|
fs = FileShare()
|
|
|
|
fs.username = request.user.username
|
|
|
|
fs.repo_id = repo_id
|
|
|
|
fs.path = path
|
|
|
|
fs.token = token
|
|
|
|
|
|
|
|
try:
|
|
|
|
fs.save()
|
|
|
|
except IntegrityError, e:
|
2012-12-23 14:27:16 +00:00
|
|
|
return api_err(status.HTTP_500_INTERNAL_SERVER_ERROR, e.msg)
|
2012-12-14 12:53:36 +00:00
|
|
|
|
2012-12-23 14:27:16 +00:00
|
|
|
http_or_https = request.is_secure() and 'https' or 'http'
|
2012-12-14 12:53:36 +00:00
|
|
|
domain = RequestSite(request).domain
|
2012-12-23 14:27:16 +00:00
|
|
|
file_shared_link = '%s://%s%sf/%s/' % (http_or_https, domain,
|
|
|
|
settings.SITE_ROOT, token)
|
2012-12-14 12:53:36 +00:00
|
|
|
return Response(file_shared_link)
|
|
|
|
|
|
|
|
def get_repo_file(request, repo_id, file_id, file_name, op):
|
|
|
|
if op == 'download':
|
|
|
|
token = seafserv_rpc.web_get_access_token(repo_id, file_id,
|
|
|
|
op, request.user.username)
|
|
|
|
redirect_url = gen_file_get_url(token, file_name)
|
2012-12-16 14:34:52 +00:00
|
|
|
#return Response(redirect_url)
|
|
|
|
response = HttpResponse(json.dumps(redirect_url), status=200,
|
|
|
|
content_type=json_content_type)
|
|
|
|
response["oid"] = file_id
|
|
|
|
return response
|
2012-12-14 12:53:36 +00:00
|
|
|
|
|
|
|
if op == 'sharelink':
|
|
|
|
path = request.GET.get('p', None)
|
|
|
|
assert path, 'path must be passed in the url'
|
|
|
|
return get_shared_link(request, repo_id, path)
|
|
|
|
|
2012-12-23 14:27:16 +00:00
|
|
|
def reloaddir(request, repo_id, parent_dir):
|
2012-12-14 12:53:36 +00:00
|
|
|
current_commit = get_commits(repo_id, 0, 1)[0]
|
2012-12-19 02:58:14 +00:00
|
|
|
if not current_commit:
|
2012-12-23 14:27:16 +00:00
|
|
|
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
|
|
'Failed to get current commit of repo %s.' % repo_id)
|
2012-12-19 02:58:14 +00:00
|
|
|
|
2012-12-14 12:53:36 +00:00
|
|
|
try:
|
|
|
|
dir_id = seafserv_threaded_rpc.get_dirid_by_path(current_commit.id,
|
|
|
|
parent_dir.encode('utf-8'))
|
|
|
|
except SearpcError, e:
|
2012-12-23 14:27:16 +00:00
|
|
|
return api_error(HTTP_520_OPERATION_FAILED,
|
|
|
|
"Failed to get dir id by path")
|
2012-12-14 12:53:36 +00:00
|
|
|
|
|
|
|
if not dir_id:
|
2012-12-23 14:27:16 +00:00
|
|
|
return api_error(status.HTTP_404_NOT_FOUND, "Path does not exist")
|
|
|
|
|
2012-12-14 12:53:36 +00:00
|
|
|
return get_dir_entrys_by_id(request, dir_id)
|
|
|
|
|
2012-12-23 14:27:16 +00:00
|
|
|
def reloaddir_if_neccessary (request, repo_id, parent_dir):
|
2013-01-16 17:38:39 +00:00
|
|
|
|
|
|
|
reload_dir = False
|
2012-12-23 14:27:16 +00:00
|
|
|
s = request.GET.get('reloaddir', None)
|
|
|
|
if s and s.lower() == 'true':
|
2013-01-16 17:38:39 +00:00
|
|
|
reload_dir = True
|
2012-12-23 14:27:16 +00:00
|
|
|
|
2013-01-16 17:38:39 +00:00
|
|
|
if not reload_dir:
|
2012-12-23 14:27:16 +00:00
|
|
|
return Response('success')
|
|
|
|
|
2013-01-16 17:38:39 +00:00
|
|
|
return reloaddir(request, repo_id, parent_dir)
|
2012-12-23 14:27:16 +00:00
|
|
|
|
2012-12-29 02:31:23 +00:00
|
|
|
# deprecated
|
2012-12-14 12:53:36 +00:00
|
|
|
class OpDeleteView(APIView):
|
|
|
|
"""
|
|
|
|
Delete a file.
|
|
|
|
"""
|
|
|
|
authentication_classes = (TokenAuthentication, )
|
2012-12-19 08:39:50 +00:00
|
|
|
permission_classes = (IsAuthenticated, IsRepoWritable, )
|
2012-12-14 12:53:36 +00:00
|
|
|
|
|
|
|
def post(self, request, repo_id, format=None):
|
2012-12-25 03:09:34 +00:00
|
|
|
repo = get_repo(repo_id)
|
|
|
|
if not repo:
|
|
|
|
return api_error(status.HTTP_404_NOT_FOUND, 'Repo not found.')
|
|
|
|
|
|
|
|
resp = check_repo_access_permission(request, repo)
|
2012-12-14 12:53:36 +00:00
|
|
|
if resp:
|
|
|
|
return resp
|
|
|
|
|
|
|
|
parent_dir = request.GET.get('p', '/')
|
|
|
|
file_names = request.POST.get("file_names")
|
|
|
|
|
|
|
|
if not parent_dir or not file_names:
|
2012-12-23 14:27:16 +00:00
|
|
|
return api_error(status.HTTP_404_NOT_FOUND,
|
|
|
|
'File or directory not found.')
|
2012-12-14 12:53:36 +00:00
|
|
|
|
2013-02-23 13:05:03 +00:00
|
|
|
for file_name in file_names.split(':'):
|
|
|
|
file_name = unquote(file_name.encode('utf-8'))
|
2012-12-14 12:53:36 +00:00
|
|
|
try:
|
|
|
|
seafserv_threaded_rpc.del_file(repo_id, parent_dir,
|
|
|
|
file_name, request.user.username)
|
|
|
|
except SearpcError,e:
|
2012-12-23 14:27:16 +00:00
|
|
|
return api_error(HTTP_520_OPERATION_FAILED,
|
|
|
|
"Failed to delete file.")
|
2012-12-14 12:53:36 +00:00
|
|
|
|
|
|
|
return reloaddir_if_neccessary (request, repo_id, parent_dir)
|
|
|
|
|
|
|
|
def append_starred_files(array, files):
|
|
|
|
for f in files:
|
|
|
|
sfile = {'org' : f.org_id,
|
|
|
|
'repo' : f.repo.id,
|
|
|
|
'path' : f.path,
|
|
|
|
'mtime' : f.last_modified,
|
|
|
|
'dir' : f.is_dir,
|
|
|
|
'size' : f.size
|
|
|
|
}
|
|
|
|
array.append(sfile)
|
|
|
|
|
|
|
|
def api_starred_files(request):
|
|
|
|
starred_files = []
|
|
|
|
personal_files = get_starred_files(request.user.username, -1)
|
|
|
|
append_starred_files (starred_files, personal_files)
|
|
|
|
return Response(starred_files)
|
|
|
|
|
|
|
|
class StarredFileView(APIView):
|
|
|
|
"""
|
2012-12-23 14:27:16 +00:00
|
|
|
Support uniform interface for starred file operation,
|
|
|
|
including add/delete/list starred files.
|
2012-12-14 12:53:36 +00:00
|
|
|
"""
|
|
|
|
|
|
|
|
authentication_classes = (TokenAuthentication, )
|
|
|
|
permission_classes = (IsAuthenticated,)
|
2012-12-26 03:03:38 +00:00
|
|
|
throttle_classes = (UserRateThrottle, )
|
2012-12-14 12:53:36 +00:00
|
|
|
|
|
|
|
def get(self, request, format=None):
|
2012-12-23 14:27:16 +00:00
|
|
|
# list starred files
|
2012-12-14 12:53:36 +00:00
|
|
|
return api_starred_files(request)
|
|
|
|
|
2012-12-23 14:27:16 +00:00
|
|
|
def post(self, request, format=None):
|
|
|
|
# add starred file
|
|
|
|
repo_id = request.POST.get('repo_id', '')
|
2013-02-25 08:39:20 +00:00
|
|
|
path = unquote(request.POST.get('p', '').encode('utf-8'))
|
2012-12-23 14:27:16 +00:00
|
|
|
if not (repo_id and path):
|
|
|
|
return api_error(status.HTTP_400_BAD_REQUEST,
|
|
|
|
'Repo_id or path is missing.')
|
|
|
|
|
|
|
|
if path[-1] == '/': # Should not contain '/' at the end of path.
|
|
|
|
return api_error(status.HTTP_400_BAD_REQUEST, 'Invalid file path.')
|
|
|
|
|
|
|
|
star_file(request.user.username, repo_id, path, is_dir=False,
|
|
|
|
org_id=-1)
|
|
|
|
|
|
|
|
resp = Response('success', status=status.HTTP_201_CREATED)
|
|
|
|
resp['Location'] = reverse('starredfiles')
|
|
|
|
|
|
|
|
return resp
|
|
|
|
|
|
|
|
def delete(self, request, format=None):
|
|
|
|
# remove starred file
|
|
|
|
repo_id = request.GET.get('repo_id', '')
|
|
|
|
path = request.GET.get('p', '')
|
|
|
|
if not (repo_id and path):
|
|
|
|
return api_error(status.HTTP_400_BAD_REQUEST,
|
|
|
|
'Repo_id or path is missing.')
|
|
|
|
|
|
|
|
if path[-1] == '/': # Should not contain '/' at the end of path.
|
|
|
|
return api_error(status.HTTP_400_BAD_REQUEST, 'Invalid file path.')
|
|
|
|
|
|
|
|
unstar_file(request.user.username, repo_id, path)
|
|
|
|
return Response('success', status=status.HTTP_200_OK)
|
|
|
|
|
|
|
|
class FileView(APIView):
|
|
|
|
"""
|
|
|
|
Support uniform interface for file related operations,
|
|
|
|
including create/delete/rename/view, etc.
|
|
|
|
"""
|
|
|
|
|
|
|
|
authentication_classes = (TokenAuthentication, )
|
|
|
|
permission_classes = (IsAuthenticated, IsRepoWritable, )
|
2012-12-26 03:03:38 +00:00
|
|
|
throttle_classes = (UserRateThrottle, )
|
2012-12-23 14:27:16 +00:00
|
|
|
|
|
|
|
def get(self, request, repo_id, format=None):
|
|
|
|
# view file
|
|
|
|
repo = get_repo(repo_id)
|
2012-12-25 03:09:34 +00:00
|
|
|
if not repo:
|
|
|
|
return api_error(status.HTTP_404_NOT_FOUND, 'Repo not found.')
|
|
|
|
|
2012-12-23 14:27:16 +00:00
|
|
|
resp = check_repo_access_permission(request, repo)
|
|
|
|
if resp:
|
|
|
|
return resp
|
|
|
|
|
|
|
|
path = request.GET.get('p', None)
|
|
|
|
if not path:
|
|
|
|
return api_error(status.HTTP_400_BAD_REQUEST, 'Path is missing.')
|
|
|
|
file_name = os.path.basename(path)
|
|
|
|
|
|
|
|
file_id = None
|
|
|
|
try:
|
2012-12-24 08:53:32 +00:00
|
|
|
file_id = seafserv_threaded_rpc.get_file_id_by_path(repo_id,
|
2012-12-23 14:27:16 +00:00
|
|
|
path.encode('utf-8'))
|
|
|
|
except SearpcError, e:
|
|
|
|
return api_error(HTTP_520_OPERATION_FAILED,
|
|
|
|
"Failed to get file id by path.")
|
|
|
|
|
|
|
|
if not file_id:
|
|
|
|
return api_error(status.HTTP_404_NOT_FOUND, "File not found")
|
|
|
|
|
|
|
|
return get_repo_file(request, repo_id, file_id, file_name, 'download')
|
|
|
|
|
|
|
|
def post(self, request, repo_id, format=None):
|
|
|
|
# rename or move file
|
2012-12-25 03:09:34 +00:00
|
|
|
repo = get_repo(repo_id)
|
|
|
|
if not repo:
|
|
|
|
return api_error(status.HTTP_404_NOT_FOUND, 'Repo not found.')
|
|
|
|
|
|
|
|
resp = check_repo_access_permission(request, repo)
|
2012-12-23 14:27:16 +00:00
|
|
|
if resp:
|
|
|
|
return resp
|
|
|
|
|
|
|
|
path = request.GET.get('p', '')
|
|
|
|
if not path or path[0] != '/':
|
|
|
|
return api_error(status.HTTP_400_BAD_REQUEST,
|
|
|
|
'Path is missing or invalid.')
|
|
|
|
|
|
|
|
operation = request.POST.get('operation', '')
|
|
|
|
if operation.lower() == 'rename':
|
|
|
|
newname = request.POST.get('newname', '')
|
|
|
|
if not newname:
|
|
|
|
return api_error(status.HTTP_400_BAD_REQUEST,
|
|
|
|
'Newname is missing')
|
2013-02-25 07:04:13 +00:00
|
|
|
newname = unquote(newname.encode('utf-8'))
|
2012-12-23 14:27:16 +00:00
|
|
|
if len(newname) > settings.MAX_UPLOAD_FILE_NAME_LEN:
|
|
|
|
return api_error(status.HTTP_400_BAD_REQUEST, 'Newname too long')
|
|
|
|
|
|
|
|
parent_dir = os.path.dirname(path)
|
2013-02-25 07:04:13 +00:00
|
|
|
parent_dir_utf8 = parent_dir.encode('utf-8')
|
2012-12-23 14:27:16 +00:00
|
|
|
oldname = os.path.basename(path)
|
2013-02-25 07:04:13 +00:00
|
|
|
oldname_utf8 = oldname.encode('utf-8')
|
2012-12-23 14:27:16 +00:00
|
|
|
if oldname == newname:
|
|
|
|
return api_error(status.HTTP_409_CONFLICT,
|
|
|
|
'The new name is the same to the old')
|
|
|
|
|
|
|
|
newname = check_filename_with_rename(repo_id, parent_dir, newname)
|
2013-02-25 08:39:20 +00:00
|
|
|
newname_utf8 = newname.encode('utf-8')
|
2012-12-23 14:27:16 +00:00
|
|
|
try:
|
|
|
|
seafserv_threaded_rpc.rename_file (repo_id, parent_dir_utf8,
|
|
|
|
oldname_utf8, newname,
|
|
|
|
request.user.username)
|
|
|
|
except SearpcError,e:
|
|
|
|
return api_error(HTTP_520_OPERATION_FAILED,
|
2013-02-25 07:04:13 +00:00
|
|
|
"Failed to rename file: %s" % e)
|
2012-12-23 14:27:16 +00:00
|
|
|
|
|
|
|
if request.GET.get('reloaddir', '').lower() == 'true':
|
|
|
|
reloaddir(request, repo_id, parent_dir)
|
|
|
|
else:
|
|
|
|
resp = Response('success', status=status.HTTP_301_MOVED_PERMANENTLY)
|
|
|
|
uri = reverse('FileView', args=[repo_id], request=request)
|
2013-02-25 08:39:20 +00:00
|
|
|
resp['Location'] = uri + '?p=' + quote(parent_dir_utf8) + quote(newname_utf8)
|
2012-12-23 14:27:16 +00:00
|
|
|
return resp
|
|
|
|
|
|
|
|
elif operation.lower() == 'move':
|
|
|
|
src_dir = os.path.dirname(path)
|
2013-02-25 07:04:13 +00:00
|
|
|
src_dir_utf8 = src_dir.encode('utf-8')
|
2012-12-23 14:27:16 +00:00
|
|
|
src_repo_id = repo_id
|
|
|
|
dst_repo_id = request.POST.get('dst_repo', '')
|
2013-02-25 07:04:13 +00:00
|
|
|
dst_dir = request.POST.get('dst_dir', '')
|
|
|
|
dst_dir_utf8 = dst_dir.encode('utf-8')
|
2012-12-23 14:27:16 +00:00
|
|
|
if dst_dir[-1] != '/': # Append '/' to the end of directory if necessary
|
|
|
|
dst_dir += '/'
|
|
|
|
# obj_names = request.POST.get('obj_names', '')
|
|
|
|
|
|
|
|
if not (dst_repo_id and dst_dir):
|
|
|
|
return api_error(status.HTTP_400_BAD_REQUEST, 'Missing arguments.')
|
|
|
|
|
|
|
|
if src_repo_id == dst_repo_id and src_dir == dst_dir:
|
|
|
|
return Response('success', status=status.HTTP_200_OK)
|
|
|
|
|
|
|
|
# names = obj_names.split(':')
|
|
|
|
# names = map(lambda x: unquote(x).decode('utf-8'), names)
|
|
|
|
|
|
|
|
# if dst_dir.startswith(src_dir):
|
|
|
|
# for obj_name in names:
|
|
|
|
# if dst_dir.startswith('/'.join([src_dir, obj_name])):
|
|
|
|
# return api_error(status.HTTP_409_CONFLICT,
|
|
|
|
# 'Can not move a dirctory to its subdir')
|
|
|
|
|
|
|
|
filename = os.path.basename(path)
|
2013-02-25 07:04:13 +00:00
|
|
|
filename_utf8 = filename.encode('utf-8')
|
2012-12-23 14:27:16 +00:00
|
|
|
new_filename = check_filename_with_rename(dst_repo_id, dst_dir,
|
|
|
|
filename)
|
2013-02-25 07:04:13 +00:00
|
|
|
new_filename_utf8 = new_filename.encode('utf-8')
|
2012-12-23 14:27:16 +00:00
|
|
|
|
|
|
|
try:
|
|
|
|
seafserv_threaded_rpc.move_file(src_repo_id, src_dir_utf8,
|
|
|
|
filename_utf8, dst_repo_id,
|
|
|
|
dst_dir_utf8, new_filename_utf8,
|
|
|
|
request.user.username)
|
|
|
|
except SearpcError, e:
|
|
|
|
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
|
|
"SearpcError:" + e.msg)
|
|
|
|
|
|
|
|
if request.GET.get('reloaddir', '').lower() == 'true':
|
|
|
|
reloaddir(request, dst_repo_id, dst_dir)
|
|
|
|
else:
|
|
|
|
resp = Response('success', status=status.HTTP_301_MOVED_PERMANENTLY)
|
|
|
|
uri = reverse('FileView', args=[repo_id], request=request)
|
|
|
|
resp['Location'] = uri + '?p=' + quote(dst_dir_utf8) + quote(new_filename_utf8)
|
|
|
|
return resp
|
|
|
|
else:
|
|
|
|
return api_error(status.HTTP_400_BAD_REQUEST,
|
|
|
|
"Operation can only be rename or move.")
|
|
|
|
|
|
|
|
def put(self, request, repo_id, format=None):
|
|
|
|
# update file
|
|
|
|
# TODO
|
|
|
|
pass
|
|
|
|
|
|
|
|
def delete(self, request, repo_id, format=None):
|
|
|
|
# delete file
|
|
|
|
repo = get_repo(repo_id)
|
2012-12-25 03:09:34 +00:00
|
|
|
if not repo:
|
|
|
|
return api_error(status.HTTP_404_NOT_FOUND, 'Repo not found.')
|
|
|
|
|
2012-12-23 14:27:16 +00:00
|
|
|
resp = check_repo_access_permission(request, repo)
|
|
|
|
if resp:
|
|
|
|
return resp
|
|
|
|
|
|
|
|
path = request.GET.get('p', None)
|
|
|
|
if not path:
|
|
|
|
return api_error(status.HTTP_400_BAD_REQUEST, 'Path is missing.')
|
|
|
|
|
|
|
|
parent_dir = os.path.dirname(path)
|
2013-02-25 07:04:13 +00:00
|
|
|
parent_dir_utf8 = os.path.dirname(path).encode('utf-8')
|
|
|
|
file_name_utf8 = os.path.basename(path).encode('utf-8')
|
2012-12-23 14:27:16 +00:00
|
|
|
|
|
|
|
try:
|
|
|
|
seafserv_threaded_rpc.del_file(repo_id, parent_dir_utf8,
|
|
|
|
file_name_utf8,
|
|
|
|
request.user.username)
|
|
|
|
except SearpcError, e:
|
|
|
|
return api_error(HTTP_520_OPERATION_FAILED,
|
|
|
|
"Failed to delete file.")
|
|
|
|
|
|
|
|
return reloaddir_if_neccessary(request, repo_id, parent_dir)
|
|
|
|
|
|
|
|
class FileSharedLinkView(APIView):
|
|
|
|
"""
|
|
|
|
Support uniform interface for file shared link.
|
|
|
|
"""
|
|
|
|
authentication_classes = (TokenAuthentication, )
|
|
|
|
permission_classes = (IsAuthenticated, )
|
2012-12-26 03:03:38 +00:00
|
|
|
throttle_classes = (UserRateThrottle, )
|
2012-12-23 14:27:16 +00:00
|
|
|
|
|
|
|
def put(self, request, repo_id, format=None):
|
|
|
|
# generate file shared link
|
2013-02-25 08:39:20 +00:00
|
|
|
path = unquote(request.DATA.get('p', '').encode('utf-8'))
|
2012-12-23 14:27:16 +00:00
|
|
|
if not path:
|
|
|
|
return api_error(status.HTTP_400_BAD_REQUEST, 'Path is missing.')
|
|
|
|
|
|
|
|
if path[-1] == '/':
|
|
|
|
path = path[:-1]
|
|
|
|
l = FileShare.objects.filter(repo_id=repo_id).filter(
|
|
|
|
username=request.user.username).filter(path=path)
|
|
|
|
if len(l) > 0:
|
|
|
|
fileshare = l[0]
|
|
|
|
token = fileshare.token
|
|
|
|
else:
|
|
|
|
token = gen_token(max_length=10)
|
|
|
|
|
|
|
|
fs = FileShare()
|
|
|
|
fs.username = request.user.username
|
|
|
|
fs.repo_id = repo_id
|
|
|
|
fs.path = path
|
|
|
|
fs.token = token
|
|
|
|
|
|
|
|
try:
|
|
|
|
fs.save()
|
|
|
|
except IntegrityError, e:
|
|
|
|
return api_err(status.HTTP_500_INTERNAL_SERVER_ERROR, e.msg)
|
|
|
|
|
|
|
|
http_or_https = request.is_secure() and 'https' or 'http'
|
|
|
|
domain = RequestSite(request).domain
|
|
|
|
file_shared_link = '%s://%s%sf/%s/' % (http_or_https, domain,
|
|
|
|
settings.SITE_ROOT, token)
|
|
|
|
resp = Response(status=status.HTTP_201_CREATED)
|
|
|
|
resp['Location'] = file_shared_link
|
|
|
|
return resp
|
|
|
|
|
|
|
|
class DirView(APIView):
|
|
|
|
"""
|
|
|
|
Support uniform interface for directory operations, including
|
|
|
|
create/delete/rename/list, etc.
|
|
|
|
"""
|
|
|
|
authentication_classes = (TokenAuthentication, )
|
|
|
|
permission_classes = (IsAuthenticated, IsRepoWritable, )
|
2012-12-26 03:03:38 +00:00
|
|
|
throttle_classes = (UserRateThrottle, )
|
|
|
|
|
2012-12-23 14:27:16 +00:00
|
|
|
def get(self, request, repo_id, format=None):
|
|
|
|
# list dir
|
|
|
|
repo = get_repo(repo_id)
|
2012-12-25 03:09:34 +00:00
|
|
|
if not repo:
|
|
|
|
return api_error(status.HTTP_404_NOT_FOUND, 'Repo not found.')
|
|
|
|
|
2012-12-23 14:27:16 +00:00
|
|
|
resp = check_repo_access_permission(request, repo)
|
|
|
|
if resp:
|
|
|
|
return resp
|
|
|
|
|
|
|
|
path = request.GET.get('p', '/')
|
|
|
|
if path[-1] != '/':
|
|
|
|
path = path + '/'
|
|
|
|
|
|
|
|
try:
|
2012-12-24 08:53:32 +00:00
|
|
|
dir_id = seafserv_threaded_rpc.get_dir_id_by_path(repo_id,
|
2012-12-23 14:27:16 +00:00
|
|
|
path.encode('utf-8'))
|
|
|
|
except SearpcError, e:
|
|
|
|
return api_error(HTTP_520_OPERATION_FAILED,
|
|
|
|
"Failed to get dir id by path.")
|
|
|
|
|
|
|
|
if not dir_id:
|
|
|
|
return api_error(status.HTTP_404_NOT_FOUND, "Path does not exist")
|
|
|
|
|
|
|
|
old_oid = request.GET.get('oid', None)
|
|
|
|
if old_oid and old_oid == dir_id :
|
|
|
|
response = HttpResponse(json.dumps("uptodate"), status=200,
|
|
|
|
content_type=json_content_type)
|
|
|
|
response["oid"] = dir_id
|
|
|
|
return response
|
|
|
|
else:
|
|
|
|
return get_dir_entrys_by_id(request, dir_id)
|
|
|
|
|
|
|
|
def post(self, request, repo_id, format=None):
|
|
|
|
# new dir
|
2012-12-25 03:09:34 +00:00
|
|
|
repo = get_repo(repo_id)
|
|
|
|
if not repo:
|
|
|
|
return api_error(status.HTTP_404_NOT_FOUND, 'Repo not found.')
|
|
|
|
|
|
|
|
resp = check_repo_access_permission(request, repo)
|
2012-12-23 14:27:16 +00:00
|
|
|
if resp:
|
|
|
|
return resp
|
|
|
|
path = request.GET.get('p', '')
|
|
|
|
if not path or path[0] != '/':
|
|
|
|
return api_error(status.HTTP_400_BAD_REQUEST, "Path is missing.")
|
|
|
|
|
|
|
|
if path == '/': # Can not make root dir.
|
|
|
|
return api_error(status.HTTP_400_BAD_REQUEST, "Path is invalid.")
|
|
|
|
|
|
|
|
if path[-1] == '/': # Cut out last '/' if possible.
|
|
|
|
path = path[:-1]
|
|
|
|
|
|
|
|
operation = request.POST.get('operation', '')
|
|
|
|
if operation.lower() == 'mkdir':
|
|
|
|
parent_dir = os.path.dirname(path)
|
2013-02-25 08:39:20 +00:00
|
|
|
parent_dir_utf8 = parent_dir.encode('utf-8')
|
2012-12-23 14:27:16 +00:00
|
|
|
new_dir_name = os.path.basename(path)
|
|
|
|
new_dir_name = check_filename_with_rename(repo_id, parent_dir,
|
|
|
|
new_dir_name)
|
2013-02-25 07:04:13 +00:00
|
|
|
new_dir_name_utf8 = new_dir_name.encode('utf-8')
|
|
|
|
|
2012-12-23 14:27:16 +00:00
|
|
|
try:
|
|
|
|
seafserv_threaded_rpc.post_dir(repo_id, parent_dir,
|
|
|
|
new_dir_name,
|
|
|
|
request.user.username)
|
|
|
|
except SearpcError, e:
|
|
|
|
return api_error(HTTP_520_OPERATION_FAILED,
|
|
|
|
'Failed to make directory.')
|
|
|
|
|
|
|
|
if request.GET.get('reloaddir', '').lower() == 'true':
|
2013-01-18 15:02:05 +00:00
|
|
|
resp = reloaddir(request, repo_id, parent_dir)
|
2012-12-23 14:27:16 +00:00
|
|
|
else:
|
|
|
|
resp = Response('success', status=status.HTTP_201_CREATED)
|
|
|
|
uri = reverse('DirView', args=[repo_id], request=request)
|
2013-02-25 08:39:20 +00:00
|
|
|
resp['Location'] = uri + '?p=' + quote(parent_dir_utf8) + \
|
2012-12-23 14:27:16 +00:00
|
|
|
quote(new_dir_name_utf8)
|
2013-01-18 15:02:05 +00:00
|
|
|
return resp
|
2012-12-23 14:27:16 +00:00
|
|
|
# elif operation.lower() == 'rename':
|
|
|
|
# pass
|
|
|
|
# elif operation.lower() == 'move':
|
|
|
|
# pass
|
|
|
|
else:
|
|
|
|
return api_error(status.HTTP_400_BAD_REQUEST,
|
|
|
|
"Operation not supported.")
|
|
|
|
|
|
|
|
def delete(self, request, repo_id, format=None):
|
|
|
|
# delete dir or file
|
|
|
|
repo = get_repo(repo_id)
|
2012-12-25 03:09:34 +00:00
|
|
|
if not repo:
|
|
|
|
return api_error(status.HTTP_404_NOT_FOUND, 'Repo not found.')
|
|
|
|
|
2012-12-23 14:27:16 +00:00
|
|
|
resp = check_repo_access_permission(request, repo)
|
|
|
|
if resp:
|
|
|
|
return resp
|
|
|
|
|
|
|
|
path = request.GET.get('p', None)
|
|
|
|
if not path:
|
|
|
|
return api_error(status.HTTP_400_BAD_REQUEST, 'Path is missing.')
|
|
|
|
|
|
|
|
if path == '/': # Can not delete root path.
|
|
|
|
return api_error(status.HTTP_400_BAD_REQUEST, 'Path is invalid.')
|
|
|
|
|
|
|
|
if path[-1] == '/': # Cut out last '/' if possible.
|
|
|
|
path = path[:-1]
|
|
|
|
|
|
|
|
parent_dir = os.path.dirname(path)
|
2013-02-25 07:04:13 +00:00
|
|
|
parent_dir_utf8 = os.path.dirname(path).encode('utf-8')
|
|
|
|
file_name_utf8 = os.path.basename(path).encode('utf-8')
|
2012-12-23 14:27:16 +00:00
|
|
|
|
|
|
|
try:
|
|
|
|
seafserv_threaded_rpc.del_file(repo_id, parent_dir_utf8,
|
|
|
|
file_name_utf8,
|
|
|
|
request.user.username)
|
|
|
|
except SearpcError, e:
|
|
|
|
return api_error(HTTP_520_OPERATION_FAILED,
|
|
|
|
"Failed to delete file.")
|
|
|
|
|
|
|
|
return reloaddir_if_neccessary(request, repo_id, parent_dir)
|
2013-02-20 12:51:37 +00:00
|
|
|
|
|
|
|
class SharedRepos(APIView):
|
|
|
|
"""
|
2013-02-25 03:36:32 +00:00
|
|
|
List repos that a user share to others/groups/public.
|
2013-02-20 12:51:37 +00:00
|
|
|
"""
|
|
|
|
authentication_classes = (TokenAuthentication, )
|
2013-02-25 03:36:32 +00:00
|
|
|
permission_classes = (IsAuthenticated, )
|
2013-02-20 12:51:37 +00:00
|
|
|
throttle_classes = (UserRateThrottle, )
|
|
|
|
|
|
|
|
def get(self, request, format=None):
|
|
|
|
username = request.user.username
|
|
|
|
shared_repos = []
|
2012-12-23 14:27:16 +00:00
|
|
|
|
2013-02-20 12:51:37 +00:00
|
|
|
shared_repos += list_share_repos(username, 'from_email', -1, -1)
|
|
|
|
shared_repos += get_group_repos_by_owner(username)
|
|
|
|
if not CLOUD_MODE:
|
|
|
|
shared_repos += list_inner_pub_repos_by_owner(username)
|
|
|
|
|
|
|
|
return HttpResponse(json.dumps(shared_repos, cls=SearpcObjEncoder),
|
|
|
|
status=200, content_type=json_content_type)
|
|
|
|
|
|
|
|
class SharedRepo(APIView):
|
|
|
|
"""
|
|
|
|
Support uniform interface for shared libraries.
|
|
|
|
"""
|
|
|
|
authentication_classes = (TokenAuthentication, )
|
|
|
|
permission_classes = (IsAuthenticated, IsRepoOwner)
|
|
|
|
throttle_classes = (UserRateThrottle, )
|
|
|
|
|
|
|
|
def delete(self, request, repo_id, format=None):
|
|
|
|
"""
|
|
|
|
Unshare a library. Only repo owner can perform this operation.
|
|
|
|
"""
|
|
|
|
share_type = request.GET.get('share_type', '')
|
|
|
|
user = request.GET.get('user', '')
|
|
|
|
group_id = request.GET.get('group_id', '')
|
|
|
|
if not (share_type and user and group_id):
|
|
|
|
return api_error(status.HTTP_400_BAD_REQUEST,
|
|
|
|
'share_type and user and group_id is required.')
|
|
|
|
|
|
|
|
if share_type == 'personal':
|
|
|
|
remove_share(repo_id, request.user.username, user)
|
|
|
|
elif share_type == 'group':
|
|
|
|
unshare_group_repo(repo_id, group_id, user)
|
|
|
|
elif share_type == 'public':
|
|
|
|
unset_inner_pub_repo(repo_id)
|
|
|
|
else:
|
|
|
|
return api_error(status.HTTP_400_BAD_REQUEST,
|
|
|
|
'share_type can only be personal or group or public.')
|
|
|
|
|
|
|
|
return Response('success', status=status.HTTP_200_OK)
|
|
|
|
|