1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-06-29 00:17:18 +00:00
seahub/views.py

666 lines
20 KiB
Python

# encoding: utf-8
from django.http import HttpResponse, HttpResponseRedirect, Http404
from django.shortcuts import render_to_response, redirect
from django.core.urlresolvers import reverse
from django.template import RequestContext
from auth.decorators import login_required
from django.db import IntegrityError
from django.views.decorators.csrf import csrf_protect
from auth.forms import AuthenticationForm, PasswordResetForm, SetPasswordForm, PasswordChangeForm
from auth.tokens import default_token_generator
from pysearpc import SearpcError
from seaserv import cclient, ccnet_rpc, get_groups, get_users, get_repos, \
get_repo, get_commits, get_branches, \
seafserv_threaded_rpc, seafserv_rpc, get_binding_peerids, get_ccnetuser
from seahub.share.models import GroupShare, UserShare
from seahub.share.forms import GroupAddRepoForm
from seahub.base.accounts import CcnetUser
from forms import AddUserForm
from urllib import quote
from seahub.contacts.models import Contact
import stat
import time
import settings
def list_to_string(l):
tmp_str = ''
for e in l[:-1]:
tmp_str = tmp_str + e + ', '
tmp_str = tmp_str + l[-1]
return tmp_str
def get_httpserver_root():
# Get seafile http server address and port from settings.py,
# and cut out last '/'
if settings.HTTP_SERVER_ROOT[-1] == '/':
http_server_root = settings.HTTP_SERVER_ROOT[:-1]
else:
http_server_root = settings.HTTP_SERVER_ROOT
return http_server_root
def get_ccnetapplet_root():
# Get ccnet applet address and port from settings.py,
# and cut out last '/'
if settings.CCNET_APPLET_ROOT[-1] == '/':
ccnet_applet_root = settings.CCNET_APPLET_ROOT[:-1]
else:
ccnet_applet_root = settings.CCNET_APPLET_ROOT
return ccnet_applet_root
def gen_token():
# Generate short token used for owner to access repo file
from django.utils.hashcompat import sha_constructor
token = sha_constructor(settings.SECRET_KEY + unicode(time.time())).hexdigest()[::8]
return token
@login_required
def root(request):
return HttpResponseRedirect(reverse(myhome))
def peers(request):
peer_type = request.REQUEST.get('type', 'all')
peer_ids = ccnet_rpc.list_peers()
peers = []
for peer_id in peer_ids.split("\n"):
# too handle the ending '\n'
if peer_id == '':
continue
peer = ccnet_rpc.get_peer(peer_id)
if peer_type == 'all':
peers.append(peer)
if peer_type == 'mypeer':
if peer.props.role_list.find('MyPeer') != -1:
peers.append(peer)
users = get_users()
return render_to_response('peers.html', {
'peers': peers,
'users': users,
}, context_instance=RequestContext(request))
def groups(request):
groups = get_groups()
return render_to_response('groups.html', {
'groups': groups,
}, context_instance=RequestContext(request))
def group(request, group_id):
"""Show a group.
Login is not required, but permission check based on token should
be added later.
"""
group = get_group(group_id)
shared_repos = GroupShare.objects.filter(group_id=group_id)
return render_to_response('group.html', {
'group': group, 'shared_repos': shared_repos,
}, context_instance=RequestContext(request))
def group_add_repo(request, group_id):
"""Add a repo to a group"""
group = get_group(group_id)
if not group:
raise Http404
if request.method == 'POST':
form = GroupAddRepoForm(request.POST)
if form.is_valid():
group_repo = GroupShare()
group_repo.group_id = group_id
group_repo.repo_id = form.cleaned_data['repo_id']
try:
group_repo.save()
except IntegrityError:
# catch the case repo added to group before
pass
return HttpResponseRedirect(reverse('view_group', args=[group_id]))
else:
form = GroupAddRepoForm()
return render_to_response("group_add_repo.html", {
'form': form, 'group': group
}, context_instance=RequestContext(request))
def validate_owner(request, repo_id):
# check whether email in the request own the repo
return seafserv_threaded_rpc.is_repo_owner(request.user.username, repo_id)
#def check_fetched_repo(request, repo_id):
# # check whether user has fetched the repo
# peerid_list = get_binding_peerids(request.user.username)
# for peer_id in peerid_list:
# repos = seafserv_threaded_rpc.list_fetched_repos(peer_id)
# for repo in repos:
# if cmp(repo.props.id, repo_id):
# return True
#
# return False
def check_shared_repo(request, repo_id):
# check whether user has been shared this repo
repos = seafserv_threaded_rpc.list_share_repos(request.user.username, 'to_email', -1, -1)
for repo in repos:
if cmp(repo.props.id, repo_id) == 0:
return True
return False
def validate_emailuser(email):
# check whether emailuser is in the database
if ccnet_rpc.get_emailuser(email) != None:
return True
return False
def repo(request, repo_id):
# get repo web access property, if no repo access property in db, then
# assume repo ap is 'own'
repo_ap = seafserv_threaded_rpc.repo_query_access_property(repo_id)
if repo_ap == None:
repo_ap = 'own'
# if repo is 'own' and user is not staff and is not owner
# and not shared this repo, then goto 404 page..
if cmp(repo_ap, 'own') == 0 and not validate_owner(request, repo_id) \
and not check_shared_repo(request, repo_id) and not request.user.is_staff:
raise Http404
repo = get_repo(repo_id)
if repo == None:
raise Http404
is_owner = False
if request.user.is_authenticated():
if validate_owner(request, repo_id):
is_owner = True
repo_size = seafserv_threaded_rpc.server_repo_size(repo_id)
latest_commit = {}
dirs = []
if not repo.props.encrypted:
latest_commit = get_commits(repo_id, 0, 1)[0]
if not request.GET.get('root_id'):
# use HEAD commit's root id
commit = seafserv_rpc.get_commit(repo.props.head_cmmt_id)
root_id = commit.props.root_id
else:
root_id = request.GET.get('root_id')
try:
dirs = seafserv_rpc.list_dir(root_id)
for dirent in dirs:
if stat.S_ISDIR(dirent.props.mode):
dirent.is_dir = True
else:
dirent.is_dir = False
except:
pass
# used to determin whether show repo content in repo.html
# if a repo is shared to me, then I can view repo content on the web
if check_shared_repo(request, repo_id):
share_to_me = True
else:
share_to_me = False
return render_to_response('repo.html', {
"repo": repo,
"latest_commit": latest_commit,
"is_owner": is_owner,
"repo_ap": repo_ap,
"repo_size": repo_size,
"dirs": dirs,
"share_to_me": share_to_me,
}, context_instance=RequestContext(request))
def repo_history(request, repo_id):
# TODO: check permission
repo = get_repo(repo_id)
try:
current_page = int(request.GET.get('page', '1'))
per_page= int(request.GET.get('per_page', '25'))
except ValueError:
current_page = 1
per_page = 25
commits_all = get_commits(repo_id, per_page * (current_page -1), per_page + 1)
commits = commits_all[:per_page]
if len(commits_all) == per_page + 1:
page_next = True
else:
page_next = False
return render_to_response('repo_history.html', {
"repo": repo,
"commits": commits,
'current_page': current_page,
'prev_page': current_page-1,
'next_page': current_page+1,
'per_page': per_page,
'page_next': page_next,
}, context_instance=RequestContext(request))
@login_required
def repo_share(request, repo_id):
return render_to_response('repo_share.html', {
"repo": repo,
"commits": commits,
"branches": branches,
}, context_instance=RequestContext(request))
@login_required
def modify_token(request, repo_id):
if not validate_owner(request, repo_id):
return HttpResponseRedirect(reverse(repo, args=[repo_id]))
token = request.POST.get('token', '')
if token:
seafserv_threaded_rpc.set_repo_token(repo_id, token)
return HttpResponseRedirect(reverse(repo, args=[repo_id]))
@login_required
def remove_repo(request, repo_id):
if not validate_owner(request, repo_id) and not request.user.is_staff:
return render_to_response('permission_error.html', {
}, context_instance=RequestContext(request))
seafserv_threaded_rpc.remove_repo(repo_id)
return HttpResponseRedirect(request.META['HTTP_REFERER'])
@login_required
def remove_fetched_repo(request, user_id, repo_id):
if user_id and repo_id:
seafserv_threaded_rpc.remove_fetched_repo (user_id, repo_id)
return HttpResponseRedirect(request.META['HTTP_REFERER'])
@login_required
def myhome(request):
owned_repos = []
quota_usage = 0
output_msg = {}
email = request.user.username
quota_usage = seafserv_threaded_rpc.get_user_quota_usage(email)
owned_repos = seafserv_threaded_rpc.list_owned_repos(email)
# Repos that are share to me
in_repos = seafserv_threaded_rpc.list_share_repos(request.user.username, 'to_email', -1, -1)
if request.method == 'POST':
output_msg = repo_add_share(request)
contacts = Contact.objects.filter(user_email=email)
return render_to_response('myhome.html', {
"owned_repos": owned_repos,
"quota_usage": quota_usage,
"in_repos": in_repos,
"output_msg": output_msg,
"contacts": contacts,
}, context_instance=RequestContext(request))
@login_required
def ownerhome(request, owner_name):
owned_repos = []
quota_usage = 0
owned_repos = seafserv_threaded_rpc.list_owned_repos(owner_name)
quota_usage = seafserv_threaded_rpc.get_user_quota_usage(owner_name)
user_dict = user_info(request, owner_name)
return render_to_response('ownerhome.html', {
"owned_repos": owned_repos,
"quota_usage": quota_usage,
"owner": owner_name,
"user_dict": user_dict,
}, context_instance=RequestContext(request))
@login_required
def repo_set_access_property(request, repo_id):
if repo_id:
ap = request.GET.get('ap', '')
seafserv_threaded_rpc.repo_set_access_property(repo_id, ap)
return HttpResponseRedirect(request.META['HTTP_REFERER'])
@login_required
def repo_list_dir(request, repo_id):
if repo_id:
# any person visit private repo, go to 404 page
repo_ap = seafserv_threaded_rpc.repo_query_access_property(repo_id)
if repo_ap == 'private':
raise Http404
# people who is not owner visits own repo, go to 404 page
if not validate_owner(request, repo_id):
if repo_ap == 'own':
raise Http404
repo = seafserv_threaded_rpc.get_repo(repo_id)
dirs = []
encrypted = repo.props.encrypted
if not encrypted:
if not request.GET.get('root_id'): # No root id..?
# ..use HEAD commit's root id
commit = seafserv_rpc.get_commit(repo.props.head_cmmt_id)
root_id = commit.props.root_id
else:
root_id = request.GET.get('root_id')
try:
dirs = seafserv_rpc.list_dir(root_id)
for dirent in dirs:
if stat.S_ISDIR(dirent.props.mode):
dirent.is_dir = True
else:
dirent.is_dir = False
except:
pass
return render_to_response('repo_dir.html', {
"repo_id": repo_id,
"dirs": dirs,
"encrypted": encrypted,
},
context_instance=RequestContext(request))
def repo_operation_file(request, op, repo_id, obj_id):
if repo_id:
# if a repo doesn't have access property in db, then assume it's 'own'
repo_ap = seafserv_threaded_rpc.repo_query_access_property(repo_id)
if not repo_ap:
repo_ap = 'own'
# if a repo is shared to me, then I can view and download file no mater whether
# repo's access property is 'own' or 'public'
if check_shared_repo(request, repo_id):
share_to_me = True
else:
share_to_me = False
token = ''
if repo_ap == 'own':
# people who is owner or this repo is shared to him, can visit the repo;
# others, just go to 404 page
if validate_owner(request, repo_id) or share_to_me:
# owner should get a token to visit repo
token = gen_token()
# put token into memory in seaf-server
seafserv_rpc.web_save_access_token(token, obj_id)
else:
raise Http404
http_server_root = get_httpserver_root()
file_name = request.GET.get('file_name', '')
return HttpResponseRedirect('%s/%s?id=%s&filename=%s&op=%s&t=%s' %
(http_server_root,
repo_id, obj_id,
file_name, op, token))
@login_required
def repo_add_share(request):
output_msg = {}
if request.method == 'POST':
from_email = request.user.username
repo_id = request.POST.get('share_repo_id', '')
to_email_list = request.POST.get('to_email', '').split(',')
info_emails = []
err_emails = []
for to_email in to_email_list:
to_email = to_email.strip(' ')
if not to_email:
continue
if validate_emailuser(to_email) and validate_owner(request, repo_id):
seafserv_threaded_rpc.add_share(repo_id, from_email, to_email, 'rw')
info_emails.append(to_email)
else:
err_emails.append(to_email)
if info_emails:
output_msg['info_msg'] = u'共享给%s成功,' % list_to_string(info_emails)
if err_emails:
output_msg['err_msg'] = u'共享给%s失败:用户不存在' % list_to_string(err_emails)
return output_msg
@login_required
def repo_list_share(request):
username = request.user.username
out_repos = seafserv_threaded_rpc.list_share_repos(username, 'from_email', -1, -1)
return render_to_response('share_repos.html', {
"out_repos": out_repos,
}, context_instance=RequestContext(request))
@login_required
def repo_download(request):
repo_id = request.GET.get('repo_id', '')
repo = seafserv_threaded_rpc.get_repo(repo_id)
repo_name = repo.props.name
quote_repo_name = quote(repo_name)
encrypted = repo.props.encrypted
if encrypted:
enc = '1'
else:
enc = ''
relay_id = cclient.props.id
ccnet_applet_root = get_ccnetapplet_root()
redirect_url = "%s/repo/download/?repo_id=%s&relay_id=%s&repo_name=%s&encrypted=%s" % (
ccnet_applet_root, repo_id, relay_id, quote_repo_name, enc)
return HttpResponseRedirect(redirect_url)
@login_required
def repo_remove_share(request):
repo_id = request.GET.get('repo_id', '')
if not validate_owner(request, repo_id):
raise Http404
to_email = request.GET.get('to_email', '')
from_email = request.user.username
seafserv_threaded_rpc.remove_share(repo_id, from_email, to_email)
return HttpResponseRedirect(request.META['HTTP_REFERER'])
@login_required
def mypeers(request):
cid = get_user_cid(request.user)
@login_required
def seafadmin(request):
if not request.user.is_staff:
raise Http404
# Make sure page request is an int. If not, deliver first page.
try:
current_page = int(request.GET.get('page', '1'))
per_page= int(request.GET.get('per_page', '25'))
except ValueError:
current_page = 1
per_page = 25
repos_all = seafserv_threaded_rpc.get_repo_list(per_page * (current_page -1), per_page + 1)
repos = repos_all[:per_page]
if len(repos_all) == per_page + 1:
page_next = True
else:
page_next = False
for repo in repos:
try:
repo.owner = seafserv_threaded_rpc.get_repo_owner(repo.props.id)
except:
repo.owner = None
return render_to_response(
'repos.html', {
'repos': repos,
'current_page': current_page,
'prev_page': current_page-1,
'next_page': current_page+1,
'per_page': per_page,
'page_next': page_next,
},
context_instance=RequestContext(request))
@login_required
def useradmin(request):
if not request.user.is_staff:
raise Http404
users = ccnet_rpc.get_emailusers(-1,-1)
for user in users:
if user.props.id == request.user.id:
user.is_self = True
return render_to_response(
'useradmin.html', {
'users': users,
},
context_instance=RequestContext(request))
@login_required
def user_info(request, email):
if not request.user.is_staff:
raise Http404
user_dict = {}
owned_repos = []
quota_usage = 0
owned_repos = seafserv_threaded_rpc.list_owned_repos(email)
quota_usage = seafserv_threaded_rpc.get_user_quota_usage(email)
try:
peers = ccnet_rpc.get_peers_by_email(email)
for peer in peers:
if not peer:
continue
peername = peer.props.name
roles = peer.props.role_list
user_dict[peername] = roles
except:
pass
# Repos that are share to user
in_repos = seafserv_threaded_rpc.list_share_repos(email, 'to_email', -1, -1)
return render_to_response(
'userinfo.html', {
'owned_repos': owned_repos,
'quota_usage': quota_usage,
"in_repos": in_repos,
'user_dict': user_dict,
'email': email
},
context_instance=RequestContext(request))
@login_required
def role_add(request, user_id):
if not request.user.is_staff:
raise Http404
if request.method == 'POST':
role = request.POST.get('role', '')
if role and len(role) <= 16:
ccnet_rpc.add_role(user_id, role)
return HttpResponseRedirect(request.META['HTTP_REFERER'])
@login_required
def role_remove(request, user_id):
if not request.user.is_staff:
raise Http404
role = request.REQUEST.get('role', '')
if role and len(role) <= 16:
ccnet_rpc.remove_role(user_id, role)
return HttpResponseRedirect(request.META['HTTP_REFERER'])
@login_required
def user_remove(request, user_id):
"""The user id is emailuser id."""
if not request.user.is_staff:
raise Http404
ccnetuser = get_ccnetuser(userid=int(user_id))
ccnetuser.delete()
return HttpResponseRedirect(request.META['HTTP_REFERER'])
@login_required
def activate_user(request, user_id):
"""The user id is emailuser id."""
if not request.user.is_staff:
raise Http404
ccnetuser = get_ccnetuser(userid=int(user_id))
ccnetuser.is_active = True
ccnetuser.save()
return HttpResponseRedirect(request.META['HTTP_REFERER'])
@login_required
def user_add(request):
"""Add a user"""
if not request.user.is_staff:
raise Http404
if request.method == 'POST':
form = AddUserForm(request.POST)
if form.is_valid():
email = form.cleaned_data['email']
password = form.cleaned_data['password1']
ccnetuser = CcnetUser(username=email, raw_password=password)
ccnetuser.is_active = True
ccnetuser.save()
return HttpResponseRedirect(reverse('useradmin', args=[]))
else:
form = AddUserForm()
return render_to_response("add_user_form.html", {
'form': form,
}, context_instance=RequestContext(request))
def back_local(request):
ccnet_applt_root = get_ccnetapplet_root()
redirect_url = '%s/home/' % ccnet_applt_root
return HttpResponseRedirect(redirect_url)