# encoding: utf-8
import os
import simplejson as json
import sys
from django.core.urlresolvers import reverse
from django.contrib import messages
from django.core.mail import send_mail
from django.contrib.sites.models import Site, RequestSite
from django.http import HttpResponse, HttpResponseBadRequest, Http404, \
HttpResponseRedirect
from django.shortcuts import render_to_response
from django.template import Context, loader, RequestContext
from django.utils.translation import ugettext as _
from auth.decorators import login_required
from pysearpc import SearpcError
from seaserv import ccnet_threaded_rpc, seafserv_threaded_rpc, get_repo, \
get_orgs_by_user, get_org_repos, list_org_inner_pub_repos, \
get_org_by_url_prefix, create_org, get_user_current_org, add_org_user, \
remove_org_user, get_org_groups, is_valid_filename, org_user_exists, \
create_org_repo, get_org_id_by_group, get_org_groups_by_user, \
get_org_users_by_url_prefix, list_org_shared_repos, is_personal_repo
from decorators import org_staff_required
from forms import OrgCreateForm
from signals import org_user_added
from utils import validate_org_repo_owner
from notifications.models import UserNotification
from share.models import FileShare
from share.forms import RepoShareForm
from registration.models import RegistrationProfile
from seahub.base.accounts import User
from seahub.contacts import Contact
from seahub.forms import RepoCreateForm, SharedRepoCreateForm
import seahub.settings as seahub_settings
from seahub.utils import render_error, render_permission_error, gen_token, \
validate_group_name, string2list, calculate_repo_last_modify, MAX_INT
from seahub.views import myhome
@login_required
def create_org(request):
"""
Create org account.
"""
if request.method == 'POST':
form = OrgCreateForm(request.POST)
if form.is_valid():
org_name = form.cleaned_data['org_name']
url_prefix = form.cleaned_data['url_prefix']
username = request.user.username
try:
# create_org(org_name, url_prefix, username)
ccnet_threaded_rpc.create_org(org_name, url_prefix, username)
return HttpResponseRedirect(\
reverse(org_info, args=[url_prefix]))
except SearpcError, e:
return render_error(request, e.msg, extra_ctx={
'base_template': 'myhome_base.html',
})
else:
form = OrgCreateForm()
return render_to_response('organizations/create_org.html', {
'form': form,
}, context_instance=RequestContext(request))
@login_required
def org_info(request, url_prefix):
"""
Show org info page, list org inner pub repos.
"""
org = get_user_current_org(request.user.username, url_prefix)
if not org:
return HttpResponseRedirect(reverse(myhome))
org_members = get_org_users_by_url_prefix(url_prefix, 0, MAX_INT)
repos = list_org_inner_pub_repos(org.org_id, request.user.username)
return render_to_response('organizations/org_info.html', {
'org': org,
'org_users': org_members,
'repos': repos,
'create_shared_repo': True,
}, context_instance=RequestContext(request))
@login_required
def org_personal(request, url_prefix):
"""
Show org personal page.
"""
org = get_user_current_org(request.user.username, url_prefix)
if not org:
return HttpResponseRedirect(reverse(myhome))
user = request.user.username
# Org repos that I own
owned_repos = seafserv_threaded_rpc.list_org_repos_by_owner(org.org_id,
user)
calculate_repo_last_modify(owned_repos)
owned_repos.sort(lambda x, y: cmp(y.latest_modify, x.latest_modify))
# Org repos others shared to me
in_repos = list_org_shared_repos(org.org_id, user,'to_email', -1, -1)
# Org groups user created
groups = get_org_groups_by_user(org.org_id, user)
# Org members used in auto complete
contacts = []
org_members = get_org_users_by_url_prefix(org.url_prefix, 0, MAX_INT)
for m in org_members:
if m.email == user: # shouldn' show my'email in auto complete
continue
m.contact_email = m.email
contacts.append(m)
return render_to_response('organizations/personal.html', {
'owned_repos': owned_repos,
"in_repos": in_repos,
'org': org,
'groups': groups,
'contacts': contacts,
'create_shared_repo': False,
'allow_public_share': True,
}, context_instance=RequestContext(request))
@login_required
def org_inner_pub_repo_create(request, url_prefix):
"""
Handle ajax post to create org inner pub repo, this repo is accessiable by
all org members.
"""
if not request.is_ajax() or request.method != 'POST':
return Http404
result = {}
content_type = 'application/json; charset=utf-8'
form = SharedRepoCreateForm(request.POST)
if form.is_valid():
repo_name = form.cleaned_data['repo_name']
repo_desc = form.cleaned_data['repo_desc']
permission = form.cleaned_data['permission']
passwd = form.cleaned_data['passwd']
user = request.user.username
org = get_user_current_org(request.user.username, url_prefix)
if not org:
return HttpResponse(json.dumps(u'创建目录失败:未加入该团体'),
content_type=content_type)
try:
# create a org repo
repo_id = create_org_repo(repo_name, repo_desc, user, passwd,
org.org_id)
# set org inner pub
seafserv_threaded_rpc.set_org_inner_pub_repo(org.org_id, repo_id, permission)
except:
repo_id = None
if not repo_id:
result['error'] = u"创建目录失败"
else:
result['success'] = True
return HttpResponse(json.dumps(result), content_type=content_type)
else:
return HttpResponseBadRequest(json.dumps(form.errors),
content_type=content_type)
@login_required
def unset_org_inner_pub_repo(request, url_prefix, repo_id):
org = get_user_current_org(request.user.username, url_prefix)
if not org:
return HttpResponseRedirect(reverse(org_info, args=[url_prefix]))
try:
seafserv_threaded_rpc.unset_org_inner_pub_repo(org.org_id, repo_id)
except SearpcError:
pass
messages.add_message(request, messages.INFO, '操作成功')
return HttpResponseRedirect(reverse(org_shareadmin, args=[url_prefix]))
@login_required
def org_groups(request, url_prefix):
"""
List org groups and add org group.
"""
org = get_user_current_org(request.user.username, url_prefix)
if not org:
return HttpResponseRedirect(reverse(myhome))
if request.method == 'POST':
result = {}
content_type = 'application/json; charset=utf-8'
group_name = request.POST.get('group_name')
if not validate_group_name(group_name):
result['error'] = u'群组名称只能包含中英文字符,数字及下划线。'
return HttpResponse(json.dumps(result), content_type=content_type)
try:
e_grpname = group_name.encode('utf-8')
user = request.user.username
group_id = ccnet_threaded_rpc.create_org_group(org.org_id,
e_grpname,
user)
except SearpcError, e:
result['error'] = _(e.msg)
return HttpResponse(json.dumps(result), content_type=content_type)
return HttpResponse(json.dumps({'success': True}),
content_type=content_type)
groups = get_org_groups(org.org_id, -1, -1)
return render_to_response('organizations/org_groups.html', {
'org': org,
'groups': groups,
}, context_instance=RequestContext(request))
def send_org_user_add_mail(request, email, password, org_name):
"""
Send email when add new user.
"""
use_https = request.is_secure()
domain = RequestSite(request).domain
t = loader.get_template('organizations/org_user_add_email.html')
c = {
'user': request.user.username,
'org_name': org_name,
'email': email,
'password': password,
'domain': domain,
'protocol': use_https and 'https' or 'http',
}
try:
send_mail(u'SeaCloud注册信息', t.render(Context(c)),
None, [email], fail_silently=False)
messages.add_message(request, messages.INFO, u'邮件发送成功。')
except:
messages.add_message(request, messages.ERROR, u'邮件发送失败。')
@login_required
@org_staff_required
def org_useradmin(request, url_prefix):
"""
List and add org users.
"""
if request.method == 'POST':
emails = request.POST.get('added-member-name')
email_list = string2list(emails)
for email in email_list:
if not email or email.find('@') <= 0 :
continue
org_id = request.user.org['org_id']
try:
User.objects.get(email=email)
email = email.strip(' ')
org_id = request.user.org['org_id']
add_org_user(org_id, email, 0)
# send signal
org_user_added.send(sender=None, org_id=org_id,
from_email=request.user.username,
to_email=email)
except User.DoesNotExist:
# User is not registered, just create account and
# add that account to org
password = gen_token(max_length=6)
if Site._meta.installed:
site = Site.objects.get_current()
else:
site = RequestSite(request)
RegistrationProfile.objects.create_active_user(\
email, email, password, site, send_email=False)
add_org_user(org_id, email, 0)
if hasattr(seahub_settings, 'EMAIL_HOST'):
org_name = request.user.org['org_name']
send_org_user_add_mail(request, email, password, org_name)
# 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
users_plus_one = get_org_users_by_url_prefix(
url_prefix, per_page * (current_page - 1), per_page + 1)
if len(users_plus_one) == per_page + 1:
page_next = True
else:
page_next = False
users = users_plus_one[:per_page]
for user in users:
if user.props.id == request.user.id:
user.is_self = True
# My contacts
contacts = Contact.objects.filter(user_email=request.user.username)
return render_to_response(
'organizations/org_useradmin.html', {
'users': users,
'contacts': contacts,
'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
@org_staff_required
def org_user_remove(request, url_prefix, user):
"""
Remove org user.
"""
org_id = request.user.org['org_id']
url_prefix = request.user.org['url_prefix']
remove_org_user(org_id, user)
return HttpResponseRedirect(reverse('org_useradmin', args=[url_prefix]))
def org_msg(request):
"""
Show organization user added messages.
"""
orgmsg_list = []
notes = UserNotification.objects.filter(to_user=request.user.username)
for n in notes:
if n.msg_type == 'org_join_msg':
try:
d = json.loads(n.detail)
from_email = d['from_email']
org_name = d['org_name']
org_prefix = d['org_prefix']
org_url = reverse('org_info', args=[org_prefix])
msg = u'%s 将你加入到团体 %s' % (
from_email, org_url, org_name)
orgmsg_list.append(msg)
except json.decoder.JSONDecodeError:
# This message is not json format, just list to user.
orgmsg_list.append(n.detail)
# remove new org msg notification
UserNotification.objects.filter(to_user=request.user.username,
msg_type='org_join_msg').delete()
return render_to_response('organizations/new_msg.html', {
'orgmsg_list': orgmsg_list,
}, context_instance=RequestContext(request))
@login_required
def org_repo_create(request, url_prefix):
"""
Handle ajax post to create org repo, this repo is only accessiable by owner.
"""
if not request.is_ajax() or request.method != 'POST':
return Http404
result = {}
content_type = 'application/json; charset=utf-8'
form = RepoCreateForm(request.POST)
if form.is_valid():
repo_name = form.cleaned_data['repo_name']
repo_desc = form.cleaned_data['repo_desc']
encrypted = form.cleaned_data['encryption']
passwd = form.cleaned_data['passwd']
passwd_again = form.cleaned_data['passwd_again']
user = request.user.username
org = get_user_current_org(request.user.username, url_prefix)
if not org:
return HttpResponse(json.dumps(u'创建目录失败:未加入该团体'),
content_type=content_type)
repo_id = create_org_repo(repo_name, repo_desc, user, passwd,
org.org_id)
if not repo_id:
result['error'] = u"创建目录失败"
else:
result['success'] = True
return HttpResponse(json.dumps(result), content_type=content_type)
else:
return HttpResponseBadRequest(json.dumps(form.errors),
content_type=content_type)
@login_required
@org_staff_required
def org_seafadmin(request, url_prefix):
# 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 = get_org_repos(request.user.org['org_id'],
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
return render_to_response(
'organizations/org_seafadmin.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
@org_staff_required
def org_group_admin(request, url_prefix):
# 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
groups_plus_one = get_org_groups (request.user.org['org_id'],
per_page * (current_page -1),
per_page +1)
groups = groups_plus_one[:per_page]
if len(groups_plus_one) == per_page + 1:
page_next = True
else:
page_next = False
return render_to_response('organizations/org_group_admin.html', {
'groups': groups,
'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
@org_staff_required
def org_group_remove(request, url_prefix, group_id):
# Request header may missing HTTP_REFERER, we need to handle that case.
next = request.META.get('HTTP_REFERER', None)
if not next:
next = seahub_settings.SITE_ROOT
try:
group_id_int = int(group_id)
except ValueError:
return HttpResponseRedirect(next)
# Check whether is the org group.
org_id = get_org_id_by_group(group_id_int)
if request.user.org['org_id'] != org_id:
return render_permission_error(request, '该群组不属于当前团体',
extra_ctx={'org': request.user.org,
'base_template': 'org_base.html'})
try:
ccnet_threaded_rpc.remove_group(group_id_int, request.user.username)
seafserv_threaded_rpc.remove_repo_group(group_id_int, None)
ccnet_threaded_rpc.remove_org_group(org_id, group_id_int)
except SearpcError, e:
return render_error(request, e.msg, extra_ctx={
'org': request.user.org,
'base_template': 'org_base.html',
})
return HttpResponseRedirect(next)
@login_required
def org_repo_share(request, url_prefix):
"""
Share org repo to members or groups in current org.
"""
if request.method != 'POST':
raise Http404
org = get_user_current_org(request.user.username, url_prefix)
if not org:
return HttpResponseRedirect(reverse(myhome))
form = RepoShareForm(request.POST)
if not form.is_valid():
# TODO: may display error msg on form
raise Http404
email_or_group = form.cleaned_data['email_or_group']
repo_id = form.cleaned_data['repo_id']
permission = form.cleaned_data['permission']
from_email = request.user.username
# Test whether user is the repo owner
if not validate_org_repo_owner(org.org_id, repo_id, request.user.username):
return render_permission_error(request, u'只有目录拥有者有权共享目录',
extra_ctx={
'org': org,
'base_template': 'org_base.html',
})
share_to_list = string2list(email_or_group)
for share_to in share_to_list:
# if share_to is user name, the format is: 'example@mail.com';
# if share_to is group, the format is 'group_name '
if share_to == 'all':
''' Share to public '''
try:
seafserv_threaded_rpc.set_org_inner_pub_repo(org.org_id,
repo_id, permission)
except:
msg = u'共享到公共资料失败'
message.add_message(request, message.ERROR, msg)
continue
msg = u'共享公共资料成功,请前往共享管理查看。' % \
(reverse('org_shareadmin', args=[org.url_prefix]))
messages.add_message(request, messages.INFO, msg)
elif (share_to.split(' ')[0].find('@') == -1):
''' Share repo to group '''
# TODO: if we know group id, then we can simplly call group_share_repo
if len(share_to.split(' ')) < 2:
msg = u'共享给 %s 失败。' % share_to
messages.add_message(request, messages.ERROR, msg)
continue
group_name = share_to.split(' ')[0]
group_creator = share_to.split(' ')[1]
# get org groups the user joined
groups = get_org_groups_by_user(org.org_id, from_email)
find = False
for group in groups:
# for every group that user joined, if group name and
# group creator matchs, then has finded the group
if group.props.group_name == group_name and \
group_creator.find(group.props.creator_name) >= 0:
seafserv_threaded_rpc.add_org_group_repo(repo_id,
org.org_id,
group.id,
from_email,
permission)
find = True
msg = u'共享到 %s 成功,请前往共享管理查看。' % \
(group_name, reverse('org_shareadmin', args=[org.url_prefix]))
messages.add_message(request, messages.INFO, msg)
break
if not find:
msg = u'共享到 %s 失败。' % group_name
messages.add_message(request, messages.ERROR, msg)
else:
''' Share repo to user '''
# Test whether share_to is in this org
if not org_user_exists(org.org_id, share_to):
msg = u'共享给 %s 失败:团体中不存在该用户。' % share_to
messages.add_message(request, messages.ERROR, msg)
continue
# Record share info to db.
try:
seafserv_threaded_rpc.add_share(repo_id, from_email, share_to,
permission)
msg = u'共享给 %s 成功,请前往共享管理查看。' % \
(share_to, reverse('org_shareadmin', args=[org.url_prefix]))
messages.add_message(request, messages.INFO, msg)
except SearpcError, e:
msg = u'共享给 %s 失败。' % share_to
messages.add_message(request, messages.ERROR, msg)
continue
return HttpResponseRedirect(reverse(org_personal, args=[org.url_prefix]))
@login_required
def org_shareadmin(request, url_prefix):
"""
List personal repos I share to others, include groups and users.
"""
username = request.user.username
org = get_user_current_org(request.user.username, url_prefix)
if not org:
return HttpResponseRedirect(reverse(myhome))
shared_repos = []
# personal repos shared by this user
shared_repos += seafserv_threaded_rpc.list_org_share_repos(org.org_id,
username,
'from_email',
-1, -1)
# repos shared to groups
group_repos = seafserv_threaded_rpc.get_org_group_repos_by_owner(org.org_id,
username)
for repo in group_repos:
group = ccnet_threaded_rpc.get_group(int(repo.group_id))
if not group:
repo.props.user = ''
continue
repo.props.user = group.props.group_name
shared_repos += group_repos
# public repos shared by this user
pub_repos = seafserv_threaded_rpc.list_org_inner_pub_repos_by_owner(org.org_id,
username)
for repo in pub_repos:
repo.props.user = '所有团体成员'
shared_repos += pub_repos
for repo in shared_repos:
if repo.props.permission == 'rw':
repo.share_permission = '可读写'
elif repo.props.permission == 'r':
repo.share_permission = '只可浏览'
else:
repo.share_permission = ''
shared_repos.sort(lambda x, y: cmp(x.repo_id, y.repo_id))
# File shared links
fileshares = FileShare.objects.filter(username=request.user.username)
o_fileshares = [] # shared files in org repos
for fs in fileshares:
if not is_personal_repo(fs.repo_id):
# only list files in org repos
fs.filename = os.path.basename(fs.path)
fs.repo = get_repo(fs.repo_id)
o_fileshares.append(fs)
request.base_template = 'org_base.html'
return render_to_response('repo/share_admin.html', {
"org": org,
"shared_repos": shared_repos,
"fileshares": o_fileshares,
"protocol": request.is_secure() and 'https' or 'http',
"domain": RequestSite(request).domain,
}, context_instance=RequestContext(request))