mirror of
https://github.com/haiwen/seahub.git
synced 2025-08-30 13:23:14 +00:00
1433 lines
54 KiB
Python
1433 lines
54 KiB
Python
# -*- coding: utf-8 -*-
|
||
import logging
|
||
import os
|
||
import stat
|
||
import simplejson as json
|
||
import urllib2
|
||
from django.core.mail import send_mail
|
||
from django.core.paginator import EmptyPage, InvalidPage
|
||
from django.core.urlresolvers import reverse
|
||
from django.contrib import messages
|
||
from django.contrib.sites.models import RequestSite
|
||
from django.http import HttpResponse, HttpResponseRedirect, Http404, \
|
||
HttpResponseBadRequest
|
||
from django.shortcuts import render_to_response
|
||
from django.template import Context, loader, RequestContext
|
||
from django.template.loader import render_to_string
|
||
from django.utils.encoding import smart_str
|
||
from django.utils import datetime_safe
|
||
from django.utils.hashcompat import md5_constructor
|
||
from django.utils.translation import ugettext as _
|
||
from django.utils.translation import ungettext
|
||
|
||
from auth.decorators import login_required
|
||
import seaserv
|
||
from seaserv import ccnet_threaded_rpc, seafserv_threaded_rpc, seafserv_rpc, \
|
||
web_get_access_token, \
|
||
get_repo, get_group_repos, get_commits, is_group_user, \
|
||
get_personal_groups_by_user, get_group, get_group_members, create_repo, \
|
||
get_personal_groups, create_org_repo, get_org_group_repos, \
|
||
check_permission, is_passwd_set, remove_repo, \
|
||
unshare_group_repo, get_file_id_by_path, post_empty_file, del_file
|
||
from pysearpc import SearpcError
|
||
|
||
from decorators import group_staff_required
|
||
from models import GroupMessage, MessageReply, MessageAttachment, GroupWiki, \
|
||
PublicGroup
|
||
from forms import MessageForm, MessageReplyForm, GroupRecommendForm, \
|
||
GroupAddForm, GroupJoinMsgForm, WikiCreateForm
|
||
from signals import grpmsg_added, grpmsg_reply_added
|
||
from settings import GROUP_MEMBERS_DEFAULT_DISPLAY
|
||
from base.decorators import sys_staff_required
|
||
from base.models import FileDiscuss
|
||
from seahub.contacts.models import Contact
|
||
from seahub.contacts.signals import mail_sended
|
||
from seahub.notifications.models import UserNotification
|
||
from seahub.settings import SITE_ROOT, SITE_NAME, MEDIA_URL
|
||
from seahub.shortcuts import get_first_object_or_none
|
||
from seahub.utils import render_error, render_permission_error, string2list, \
|
||
check_and_get_org_by_group, gen_file_get_url, get_file_type_and_ext, \
|
||
get_file_contributors
|
||
from seahub.utils.file_types import IMAGE
|
||
from seahub.utils import calc_file_path_hash
|
||
from seahub.utils.paginator import Paginator
|
||
from seahub.utils.wiki import normalize_page_name, clean_page_name, get_wiki_dirent
|
||
from seahub.views import is_registered_user
|
||
from seahub.forms import SharedRepoCreateForm
|
||
|
||
# Get an instance of a logger
|
||
logger = logging.getLogger(__name__)
|
||
|
||
|
||
def is_group_staff(group, user):
|
||
if user.is_anonymous():
|
||
return False
|
||
return seaserv.check_group_staff(group.id, user.username)
|
||
|
||
|
||
def group_check(func):
|
||
"""
|
||
Decorator for initial group permission check tasks
|
||
|
||
un-login user & group not pub --> public info page
|
||
un-login user & group pub --> view_perm = "pub"
|
||
login user & non group member & group not pub --> public info page
|
||
login user & non group member & group pub --> view_perm = "pub"
|
||
group member --> view_perm = "joined"
|
||
sys admin --> view_perm = "sys_admin"
|
||
"""
|
||
def _decorated(request, group_id, *args, **kwargs):
|
||
group_id_int = int(group_id) # Checked by URL Conf
|
||
group = get_group(group_id_int)
|
||
if not group:
|
||
return HttpResponseRedirect(reverse('group_list', args=[]))
|
||
group.is_staff = False
|
||
|
||
if not request.user.is_authenticated():
|
||
if not PublicGroup.objects.filter(group_id=group_id_int):
|
||
return render_to_response('group/group_pubinfo.html', {
|
||
'group': group,
|
||
}, context_instance=RequestContext(request))
|
||
else:
|
||
group.view_perm = "pub"
|
||
return func(request, group, *args, **kwargs)
|
||
|
||
joined = is_group_user(group_id_int, request.user.username)
|
||
if joined:
|
||
group.view_perm = "joined"
|
||
group.is_staff = is_group_staff(group, request.user)
|
||
return func(request, group, *args, **kwargs)
|
||
if request.user.is_staff:
|
||
# viewed by system admin
|
||
group.view_perm = "sys_admin"
|
||
return func(request, group, *args, **kwargs)
|
||
|
||
pub = PublicGroup.objects.filter(group_id=group_id_int)
|
||
if pub:
|
||
group.view_perm = "pub"
|
||
return func(request, group, *args, **kwargs)
|
||
|
||
# Return group public info page.
|
||
return render_to_response('group/group_pubinfo.html', {
|
||
'group': group,
|
||
}, context_instance=RequestContext(request))
|
||
|
||
return _decorated
|
||
|
||
|
||
@login_required
|
||
def group_list(request):
|
||
username = request.user.username
|
||
|
||
if request.method == 'POST':
|
||
"""
|
||
Add a new group.
|
||
"""
|
||
result = {}
|
||
content_type = 'application/json; charset=utf-8'
|
||
|
||
form = GroupAddForm(request.POST)
|
||
if form.is_valid():
|
||
group_name = form.cleaned_data['group_name']
|
||
|
||
# Check whether group name is duplicated.
|
||
if request.cloud_mode:
|
||
checked_groups = get_personal_groups_by_user(username)
|
||
else:
|
||
checked_groups = get_personal_groups(-1, -1)
|
||
for g in checked_groups:
|
||
if g.group_name == group_name:
|
||
result['error'] = _(u'There is already a group with that name.')
|
||
return HttpResponse(json.dumps(result), status=400,
|
||
content_type=content_type)
|
||
|
||
# Group name is valid, create that group.
|
||
try:
|
||
ccnet_threaded_rpc.create_group(group_name.encode('utf-8'),
|
||
username)
|
||
return HttpResponse(json.dumps({'success': True}),
|
||
content_type=content_type)
|
||
except SearpcError, e:
|
||
result['error'] = _(e.msg)
|
||
return HttpResponse(json.dumps(result), status=500,
|
||
content_type=content_type)
|
||
else:
|
||
return HttpResponseBadRequest(json.dumps(form.errors),
|
||
content_type=content_type)
|
||
|
||
### GET ###
|
||
joined_groups = get_personal_groups_by_user(username)
|
||
|
||
return render_to_response('group/groups.html', {
|
||
'joined_groups': joined_groups,
|
||
}, context_instance=RequestContext(request))
|
||
|
||
@login_required
|
||
@sys_staff_required
|
||
def group_remove(request, group_id):
|
||
"""
|
||
Remove group from groupadmin page. Only system admin can perform this
|
||
operation.
|
||
"""
|
||
# Request header may missing HTTP_REFERER, we need to handle that case.
|
||
next = request.META.get('HTTP_REFERER', None)
|
||
if not next:
|
||
next = SITE_ROOT
|
||
|
||
try:
|
||
group_id_int = int(group_id)
|
||
except ValueError:
|
||
return HttpResponseRedirect(next)
|
||
|
||
try:
|
||
ccnet_threaded_rpc.remove_group(group_id_int, request.user.username)
|
||
seafserv_threaded_rpc.remove_repo_group(group_id_int, None)
|
||
except SearpcError, e:
|
||
return render_error(request, _(e.msg))
|
||
|
||
return HttpResponseRedirect(next)
|
||
|
||
@login_required
|
||
@group_staff_required
|
||
def group_dismiss(request, group_id):
|
||
"""
|
||
Dismiss a group, only group staff can perform this operation.
|
||
"""
|
||
try:
|
||
group_id_int = int(group_id)
|
||
except ValueError:
|
||
return HttpResponseRedirect(reverse('group_list', args=[]))
|
||
|
||
group = get_group(group_id_int)
|
||
if not group:
|
||
return HttpResponseRedirect(reverse('group_list', args=[]))
|
||
|
||
username = request.user.username
|
||
try:
|
||
ccnet_threaded_rpc.remove_group(group.id, username)
|
||
seafserv_threaded_rpc.remove_repo_group(group.id, None)
|
||
|
||
if request.user.org:
|
||
org_id = request.user.org['org_id']
|
||
url_prefix = request.user.org['url_prefix']
|
||
ccnet_threaded_rpc.remove_org_group(org_id, group_id_int)
|
||
return HttpResponseRedirect(reverse('org_groups',
|
||
args=[url_prefix]))
|
||
|
||
except SearpcError, e:
|
||
return render_error(request, _(e.msg))
|
||
|
||
return HttpResponseRedirect(reverse('group_list'))
|
||
|
||
@login_required
|
||
def group_make_public(request, group_id):
|
||
"""
|
||
Make a group public, only group staff can perform this operation.
|
||
"""
|
||
try:
|
||
group_id_int = int(group_id)
|
||
except ValueError:
|
||
return HttpResponseRedirect(reverse('group_list', args=[]))
|
||
|
||
group = get_group(group_id_int)
|
||
if not group:
|
||
return HttpResponseRedirect(reverse('group_list', args=[]))
|
||
|
||
# Check whether user is group staff
|
||
if not is_group_staff(group, request.user):
|
||
return render_permission_error(request, _(u'Only administrators can make the group public'))
|
||
|
||
p = PublicGroup(group_id=group.id)
|
||
p.save()
|
||
return HttpResponseRedirect(reverse('group_manage', args=[group_id]))
|
||
|
||
@login_required
|
||
def group_revoke_public(request, group_id):
|
||
"""
|
||
Revoke a group from public, only group staff can perform this operation.
|
||
"""
|
||
try:
|
||
group_id_int = int(group_id)
|
||
except ValueError:
|
||
return HttpResponseRedirect(reverse('group_list', args=[]))
|
||
|
||
group = get_group(group_id_int)
|
||
if not group:
|
||
return HttpResponseRedirect(reverse('group_list', args=[]))
|
||
|
||
# Check whether user is group staff
|
||
if not is_group_staff(group, request.user):
|
||
return render_permission_error(request, _(u'Only administrators can make the group public'))
|
||
|
||
try:
|
||
p = PublicGroup.objects.get(group_id=group.id)
|
||
p.delete()
|
||
except:
|
||
pass
|
||
|
||
return HttpResponseRedirect(reverse('group_manage', args=[group_id]))
|
||
|
||
|
||
@login_required
|
||
def group_quit(request, group_id):
|
||
try:
|
||
group_id_int = int(group_id)
|
||
except ValueError:
|
||
return HttpResponseRedirect(reverse('group_list', args=[]))
|
||
|
||
try:
|
||
ccnet_threaded_rpc.quit_group(group_id_int, request.user.username)
|
||
seafserv_threaded_rpc.remove_repo_group(group_id_int,
|
||
request.user.username)
|
||
except SearpcError, e:
|
||
return render_error(request, _(e.msg))
|
||
|
||
return HttpResponseRedirect(reverse('group_list', args=[]))
|
||
|
||
@login_required
|
||
def group_message_remove(request, group_id, msg_id):
|
||
"""
|
||
Remove group message and all message replies and attachments.
|
||
"""
|
||
# Checked by URL Conf
|
||
group_id_int = int(group_id)
|
||
msg_id = int(msg_id)
|
||
group = get_group(group_id_int)
|
||
if not group:
|
||
raise Http404
|
||
|
||
# Test whether user is in the group
|
||
if not is_group_user(group_id_int, request.user.username):
|
||
raise Http404
|
||
|
||
try:
|
||
gm = GroupMessage.objects.get(id=msg_id)
|
||
except GroupMessage.DoesNotExist:
|
||
return HttpResponse(json.dumps({'success': False, 'err_msg':_(u"The message doesn't exist")}),
|
||
content_type='application/json; charset=utf-8')
|
||
else:
|
||
# Test whether user is group admin or message owner.
|
||
if seaserv.check_group_staff(group_id, request.user.username) or \
|
||
gm.from_email == request.user.username:
|
||
gm.delete()
|
||
return HttpResponse(json.dumps({'success': True}),
|
||
content_type='application/json; charset=utf-8')
|
||
else:
|
||
return HttpResponse(json.dumps({'success': False, 'err_msg': _(u"You don't have the permission.")}),
|
||
content_type='application/json; charset=utf-8')
|
||
|
||
def msg_reply(request, msg_id):
|
||
"""Show group message replies, and process message reply in ajax"""
|
||
|
||
content_type = 'application/json; charset=utf-8'
|
||
if request.is_ajax():
|
||
ctx = {}
|
||
try:
|
||
group_msg = GroupMessage.objects.get(id=msg_id)
|
||
except GroupMessage.DoesNotExist:
|
||
return HttpResponseBadRequest(content_type=content_type)
|
||
|
||
if request.method == 'POST':
|
||
form = MessageReplyForm(request.POST)
|
||
# TODO: invalid form
|
||
if form.is_valid():
|
||
msg = form.cleaned_data['message']
|
||
|
||
msg_reply = MessageReply()
|
||
msg_reply.reply_to = group_msg
|
||
msg_reply.from_email = request.user.username
|
||
msg_reply.message = msg
|
||
msg_reply.save()
|
||
|
||
# send signal if reply other's message
|
||
if group_msg.from_email != request.user.username:
|
||
grpmsg_reply_added.send(sender=MessageReply,
|
||
msg_id=msg_id,
|
||
from_email=request.user.username)
|
||
replies = MessageReply.objects.filter(reply_to=group_msg)
|
||
r_num = len(replies)
|
||
if r_num < 4:
|
||
ctx['replies'] = replies
|
||
else:
|
||
ctx['replies'] = replies[r_num - 3:]
|
||
html = render_to_string("group/group_reply_list.html", ctx)
|
||
serialized_data = json.dumps({"r_num": r_num, "html": html})
|
||
return HttpResponse(serialized_data, content_type=content_type)
|
||
|
||
else:
|
||
replies = MessageReply.objects.filter(reply_to=group_msg)
|
||
r_num = len(replies)
|
||
ctx['replies'] = replies
|
||
html = render_to_string("group/group_reply_list.html", ctx)
|
||
serialized_data = json.dumps({"r_num": r_num, "html": html})
|
||
return HttpResponse(serialized_data, content_type=content_type)
|
||
else:
|
||
return HttpResponseBadRequest(content_type=content_type)
|
||
|
||
@login_required
|
||
def msg_reply_new(request):
|
||
notes = UserNotification.objects.filter(to_user=request.user.username)
|
||
grpmsg_reply_list = [ n.detail for n in notes if \
|
||
n.msg_type == 'grpmsg_reply']
|
||
|
||
group_msgs = []
|
||
for msg_id in grpmsg_reply_list:
|
||
try:
|
||
m = GroupMessage.objects.get(id=msg_id)
|
||
except GroupMessage.DoesNotExist:
|
||
continue
|
||
else:
|
||
# get group name
|
||
group = get_group(m.group_id)
|
||
if not group:
|
||
continue
|
||
m.group_name = group.group_name
|
||
|
||
# get attachement
|
||
attachment = get_first_object_or_none(m.messageattachment_set.all())
|
||
if attachment:
|
||
path = attachment.path
|
||
if path == '/':
|
||
repo = get_repo(attachment.repo_id)
|
||
if not repo:
|
||
continue
|
||
attachment.name = repo.name
|
||
else:
|
||
attachment.name = os.path.basename(path)
|
||
m.attachment = attachment
|
||
|
||
# get message replies
|
||
reply_list = MessageReply.objects.filter(reply_to=m)
|
||
m.reply_cnt = reply_list.count()
|
||
if m.reply_cnt > 3:
|
||
m.replies = reply_list[m.reply_cnt - 3:]
|
||
else:
|
||
m.replies = reply_list
|
||
|
||
group_msgs.append(m)
|
||
|
||
# remove new group msg reply notification
|
||
UserNotification.objects.filter(to_user=request.user.username,
|
||
msg_type='grpmsg_reply').delete()
|
||
|
||
return render_to_response("group/new_msg_reply.html", {
|
||
'group_msgs': group_msgs,
|
||
}, context_instance=RequestContext(request))
|
||
|
||
|
||
def group_info_for_pub(request, group):
|
||
return render_to_response("group/group_info_for_pub.html", {
|
||
"repos": [],
|
||
"group": group,
|
||
}, context_instance=RequestContext(request))
|
||
|
||
|
||
@group_check
|
||
def group_info(request, group):
|
||
|
||
if group.view_perm == "pub":
|
||
return group_info_for_pub(request, group)
|
||
|
||
# Get all group members.
|
||
members = get_group_members(group.id)
|
||
|
||
org = request.user.org
|
||
if org:
|
||
repos = get_org_group_repos(org['org_id'], group.id,
|
||
request.user.username)
|
||
else:
|
||
repos = get_group_repos(group.id, request.user.username)
|
||
|
||
recent_commits = []
|
||
cmt_repo_dict = {}
|
||
for repo in repos:
|
||
repo.user_perm = check_permission(repo.props.id, request.user.username)
|
||
cmmts = get_commits(repo.props.id, 0, 10)
|
||
for c in cmmts:
|
||
cmt_repo_dict[c.id] = repo
|
||
recent_commits += cmmts
|
||
|
||
recent_commits.sort(lambda x, y : cmp(y.props.ctime, x.props.ctime))
|
||
recent_commits = recent_commits[:15]
|
||
for cmt in recent_commits:
|
||
cmt.repo = cmt_repo_dict[cmt.id]
|
||
cmt.repo.password_set = is_passwd_set(cmt.props.repo_id,
|
||
request.user.username)
|
||
cmt.tp = cmt.props.desc.split(' ')[0]
|
||
|
||
return render_to_response("group/group_info.html", {
|
||
"members": members,
|
||
"repos": repos,
|
||
"recent_commits": recent_commits,
|
||
"group" : group,
|
||
"is_staff": group.is_staff,
|
||
'create_shared_repo': True,
|
||
'group_members_default_display': GROUP_MEMBERS_DEFAULT_DISPLAY,
|
||
}, context_instance=RequestContext(request))
|
||
|
||
@group_check
|
||
def group_members(request, group):
|
||
|
||
if group.view_perm == 'pub':
|
||
raise Http404
|
||
|
||
# Get all group members.
|
||
members = get_group_members(group.id)
|
||
|
||
user = request.user.username
|
||
contacts = Contact.objects.filter(user_email=user)
|
||
contact_emails = []
|
||
for c in contacts:
|
||
contact_emails.append(c.contact_email)
|
||
for m in members:
|
||
if m.user_name == user or m.user_name in contact_emails:
|
||
m.can_be_contact = False
|
||
else:
|
||
m.can_be_contact = True
|
||
|
||
return render_to_response("group/group_members.html", {
|
||
"members": members,
|
||
"group" : group,
|
||
"is_staff": group.is_staff,
|
||
}, context_instance=RequestContext(request))
|
||
|
||
@login_required
|
||
@group_staff_required
|
||
def group_manage(request, group_id):
|
||
group_id_int = int(group_id) # Checked by URL Conf
|
||
group = get_group(group_id_int)
|
||
if not group:
|
||
return HttpResponseRedirect(reverse('group_list', args=[]))
|
||
user = request.user.username
|
||
|
||
if request.method == 'POST':
|
||
"""
|
||
Add group members.
|
||
"""
|
||
result = {}
|
||
content_type = 'application/json; charset=utf-8'
|
||
|
||
member_name_str = request.POST.get('user_name', '')
|
||
member_list = string2list(member_name_str)
|
||
|
||
# Add users to contacts.
|
||
for email in member_list:
|
||
mail_sended.send(sender=None, user=user, email=email)
|
||
|
||
mail_sended_list = []
|
||
if request.cloud_mode:
|
||
if request.user.org:
|
||
# Can only invite org users to group.
|
||
org_id = request.user.org['org_id']
|
||
for email in member_list:
|
||
if not ccnet_threaded_rpc.org_user_exists(org_id, email):
|
||
err_msg = _(u'Failed to add, %s is not in current organization.') % email
|
||
result['error'] = err_msg
|
||
return HttpResponse(json.dumps(result), status=400,
|
||
content_type=content_type)
|
||
else:
|
||
try:
|
||
ccnet_threaded_rpc.group_add_member(group.id,
|
||
user, email)
|
||
except SearpcError, e:
|
||
result['error'] = _(e.msg)
|
||
return HttpResponse(json.dumps(result), status=500,
|
||
content_type=content_type)
|
||
else:
|
||
# Can invite unregistered user to group.
|
||
for email in member_list:
|
||
if not is_registered_user(email):
|
||
use_https = request.is_secure()
|
||
domain = RequestSite(request).domain
|
||
|
||
t = loader.get_template('group/add_member_email.html')
|
||
c = {
|
||
'email': user,
|
||
'to_email': email,
|
||
'group': group,
|
||
'domain': domain,
|
||
'protocol': use_https and 'https' or 'http',
|
||
'site_name': SITE_NAME,
|
||
}
|
||
|
||
try:
|
||
send_mail(_(u'Your friend added you to a group at Seafile.'),
|
||
t.render(Context(c)), None, [email],
|
||
fail_silently=False)
|
||
mail_sended_list.append(email)
|
||
except:
|
||
data = json.dumps({'error': _(u'Failed to send mail.')})
|
||
return HttpResponse(data, status=500,
|
||
content_type=content_type)
|
||
|
||
# Add user to group, unregistered user will see the group
|
||
# when he logs in.
|
||
try:
|
||
ccnet_threaded_rpc.group_add_member(group.id,
|
||
user, email)
|
||
except SearpcError, e:
|
||
result['error'] = _(e.msg)
|
||
return HttpResponse(json.dumps(result), status=500,
|
||
content_type=content_type)
|
||
else:
|
||
# Can only invite registered user to group if not in cloud mode.
|
||
for email in member_list:
|
||
if not is_registered_user(email):
|
||
err_msg = _(u'Failed to add, %s is not registerd.')
|
||
result['error'] = err_msg % email
|
||
return HttpResponse(json.dumps(result), status=400,
|
||
content_type=content_type)
|
||
# Add user to group.
|
||
try:
|
||
ccnet_threaded_rpc.group_add_member(group.id,
|
||
user, email)
|
||
except SearpcError, e:
|
||
result['error'] = _(e.msg)
|
||
return HttpResponse(json.dumps(result), status=500,
|
||
content_type=content_type)
|
||
if mail_sended_list:
|
||
msg = ungettext(
|
||
'Successfully added. An email has been sent.',
|
||
'Successfully added. %(count)s emails have been sent.',
|
||
len(mail_sended_list)) % {
|
||
'count': len(mail_sended_list),
|
||
}
|
||
messages.success(request, msg)
|
||
|
||
else:
|
||
messages.success(request, _(u'Successfully added.'))
|
||
return HttpResponse(json.dumps('success'), status=200,
|
||
content_type=content_type)
|
||
|
||
### GET ###
|
||
members_all = ccnet_threaded_rpc.get_group_members(group.id)
|
||
admins = [ m for m in members_all if m.is_staff ]
|
||
|
||
contacts = Contact.objects.filter(user_email=user)
|
||
|
||
if PublicGroup.objects.filter(group_id=group.id):
|
||
is_pub = True
|
||
else:
|
||
is_pub = False
|
||
|
||
return render_to_response('group/group_manage.html', {
|
||
'group' : group,
|
||
'members': members_all,
|
||
'admins': admins,
|
||
'contacts': contacts,
|
||
'is_pub': is_pub,
|
||
}, context_instance=RequestContext(request))
|
||
|
||
@login_required
|
||
@group_staff_required
|
||
def group_add_admin(request, group_id):
|
||
"""
|
||
Add group admin.
|
||
"""
|
||
group_id = int(group_id) # Checked by URL Conf
|
||
|
||
if request.method != 'POST' or not request.is_ajax():
|
||
raise Http404
|
||
|
||
result = {}
|
||
content_type = 'application/json; charset=utf-8'
|
||
|
||
member_name_str = request.POST.get('user_name', '')
|
||
member_list = string2list(member_name_str)
|
||
|
||
for member_name in member_list:
|
||
# Add user to contacts.
|
||
mail_sended.send(sender=None, user=request.user.username,
|
||
email=member_name)
|
||
|
||
if not is_registered_user(member_name):
|
||
err_msg = _(u'Failed to add, %s is not registrated.') % member_name
|
||
result['error'] = err_msg
|
||
return HttpResponse(json.dumps(result), status=400,
|
||
content_type=content_type)
|
||
|
||
# Check whether user is in the group
|
||
if is_group_user(group_id, member_name):
|
||
try:
|
||
ccnet_threaded_rpc.group_set_admin(group_id, member_name)
|
||
except SearpcError, e:
|
||
result['error'] = _(e.msg)
|
||
return HttpResponse(json.dumps(result), status=500,
|
||
content_type=content_type)
|
||
else:
|
||
try:
|
||
ccnet_threaded_rpc.group_add_member(group_id,
|
||
request.user.username,
|
||
member_name)
|
||
ccnet_threaded_rpc.group_set_admin(group_id, member_name)
|
||
except SearpcError, e:
|
||
result['error'] = _(e.msg)
|
||
return HttpResponse(json.dumps(result), status=500,
|
||
content_type=content_type)
|
||
messages.success(request, _(u'Operation succeeded.'))
|
||
return HttpResponse(json.dumps('success'), status=200,
|
||
content_type=content_type)
|
||
|
||
@login_required
|
||
@group_staff_required
|
||
def group_remove_admin(request, group_id):
|
||
"""
|
||
Remove group admin, and becomes normal group member.
|
||
"""
|
||
user = request.GET.get('u', '')
|
||
try:
|
||
ccnet_threaded_rpc.group_unset_admin(int(group_id), user)
|
||
messages.success(request, _(u'Operation succeeded.'))
|
||
except SearpcError, e:
|
||
messages.error(request, _(e.msg))
|
||
return HttpResponseRedirect(reverse('group_manage', args=[group_id]))
|
||
|
||
@login_required
|
||
def group_member_operations(request, group_id, user_name):
|
||
if request.GET.get('op','') == 'delete':
|
||
return group_remove_member(request, group_id, user_name)
|
||
else:
|
||
return HttpResponseRedirect(reverse('group_manage', args=[group_id]))
|
||
|
||
def group_remove_member(request, group_id, user_name):
|
||
group_id_int = int(group_id) # Checked by URLConf
|
||
|
||
group = get_group(group_id_int)
|
||
if not group:
|
||
raise Http404
|
||
|
||
if not is_group_staff(group, request.user):
|
||
raise Http404
|
||
|
||
try:
|
||
ccnet_threaded_rpc.group_remove_member(group.id,
|
||
request.user.username,
|
||
user_name)
|
||
seafserv_threaded_rpc.remove_repo_group(group.id, user_name)
|
||
messages.success(request, _(u'Operation succeeded.'))
|
||
except SearpcError, e:
|
||
messages.error(request, _(u'Failed:%s') % _(e.msg))
|
||
|
||
return HttpResponseRedirect(reverse('group_manage', args=[group_id]))
|
||
|
||
def group_share_repo(request, repo_id, group_id, from_email, permission):
|
||
"""
|
||
Share a repo to a group.
|
||
|
||
"""
|
||
# Check whether group exists
|
||
group = get_group(group_id)
|
||
if not group:
|
||
return render_error(request, _(u"Failed to share: the group doesn't exist."))
|
||
|
||
if seafserv_threaded_rpc.group_share_repo(repo_id, group_id, from_email, permission) != 0:
|
||
return render_error(request, _(u"Failed to share: internal error."))
|
||
|
||
def group_unshare_repo(request, repo_id, group_id, from_email):
|
||
"""
|
||
Unshare a repo in group.
|
||
|
||
"""
|
||
# Check whether group exists
|
||
group = get_group(group_id)
|
||
if not group:
|
||
return render_error(request, _(u"Failed to unshare: the group doesn't exist."))
|
||
|
||
# Check whether user is group staff or the one share the repo
|
||
if not seaserv.check_group_staff(group_id, from_email) and \
|
||
seafserv_threaded_rpc.get_group_repo_owner(repo_id) != from_email:
|
||
return render_permission_error(request, _(u"Operation failed: only administrators and the owner of the library can unshare it."))
|
||
|
||
if unshare_group_repo(repo_id, group_id, from_email) != 0:
|
||
return render_error(request, _(u"Failed to unshare: internal error."))
|
||
|
||
@login_required
|
||
def group_recommend(request):
|
||
"""
|
||
Recommend a file or directory to a group.
|
||
now changed to 'Discuss'
|
||
for ajax post/get
|
||
"""
|
||
content_type = 'application/json; charset=utf-8'
|
||
result = {}
|
||
if request.method == 'POST':
|
||
|
||
form = GroupRecommendForm(request.POST)
|
||
if form.is_valid():
|
||
repo_id = form.cleaned_data['repo_id']
|
||
attach_type = form.cleaned_data['attach_type']
|
||
path = form.cleaned_data['path']
|
||
message = form.cleaned_data['message']
|
||
groups = request.POST.getlist('groups') # groups is a group_id list, e.g. [u'1', u'7']
|
||
username = request.user.username
|
||
|
||
groups_not_in = []
|
||
groups_posted_to = []
|
||
for group_id in groups:
|
||
# Check group id format
|
||
try:
|
||
group_id = int(group_id)
|
||
except ValueError:
|
||
result['err'] = _(u'Error: wrong group id')
|
||
return HttpResponse(json.dumps(result), status=400, content_type=content_type)
|
||
|
||
group = get_group(group_id)
|
||
if not group:
|
||
result['err'] = _(u'Error: the group does not exist.')
|
||
return HttpResponse(json.dumps(result), status=400, content_type=content_type)
|
||
|
||
# TODO: Check whether repo is in the group and Im in the group
|
||
if not is_group_user(group_id, username):
|
||
groups_not_in.append(group.group_name)
|
||
continue
|
||
|
||
# save message to group
|
||
gm = GroupMessage(group_id=group_id, from_email=username,
|
||
message=message)
|
||
gm.save()
|
||
|
||
# send signal
|
||
grpmsg_added.send(sender=GroupMessage, group_id=group_id,
|
||
from_email=request.user.username)
|
||
|
||
# save attachment
|
||
ma = MessageAttachment(group_message=gm, repo_id=repo_id,
|
||
attach_type=attach_type, path=path,
|
||
src='recommend')
|
||
ma.save()
|
||
|
||
# save discussion
|
||
fd = FileDiscuss(group_message=gm, repo_id=repo_id, path=path)
|
||
fd.save()
|
||
|
||
group_url = reverse('group_discuss', args=[group_id])
|
||
groups_posted_to.append(u'<a href="%(url)s" target="_blank">%(name)s</a>' % \
|
||
{'url':group_url, 'name':group.group_name})
|
||
|
||
if len(groups_posted_to) > 0:
|
||
result['success'] = _(u'Successfully posted to %(groups)s.') % {'groups': ', '.join(groups_posted_to)}
|
||
|
||
if len(groups_not_in) > 0:
|
||
result['err'] = _(u'Error: you are not in group %s.') % (', '.join(groups_not_in))
|
||
|
||
else:
|
||
result['err'] = str(form.errors)
|
||
return HttpResponse(json.dumps(result), status=400, content_type=content_type)
|
||
|
||
# request.method == 'GET'
|
||
else:
|
||
repo_id = request.GET.get('repo_id')
|
||
path = request.GET.get('path', None)
|
||
repo = get_repo(repo_id)
|
||
if not repo:
|
||
result['err'] = _(u'Error: the library does not exist.')
|
||
return HttpResponse(json.dumps(result), status=400, content_type=content_type)
|
||
if path is None:
|
||
result['err'] = _(u'Error: no path.')
|
||
return HttpResponse(json.dumps(result), status=400, content_type=content_type)
|
||
|
||
# get discussions & replies
|
||
path_hash = calc_file_path_hash(path)
|
||
discussions = FileDiscuss.objects.filter(path_hash=path_hash, repo_id=repo_id)
|
||
msg_ids = [ e.group_message_id for e in discussions ]
|
||
|
||
grp_msgs = GroupMessage.objects.filter(id__in=msg_ids).order_by('-timestamp')
|
||
msg_replies = MessageReply.objects.filter(reply_to__in=grp_msgs)
|
||
for msg in grp_msgs:
|
||
msg.replies = []
|
||
for reply in msg_replies:
|
||
if msg.id == reply.reply_to_id:
|
||
msg.replies.append(reply)
|
||
msg.reply_cnt = len(msg.replies)
|
||
msg.replies = msg.replies[-3:]
|
||
|
||
ctx = {}
|
||
ctx['messages'] = grp_msgs
|
||
html = render_to_string("group/discussion_list.html", ctx)
|
||
result['html'] = html
|
||
return HttpResponse(json.dumps(result), content_type=content_type)
|
||
|
||
|
||
@login_required
|
||
def create_group_repo(request, group_id):
|
||
"""Create a repo and share it to current group"""
|
||
|
||
content_type = 'application/json; charset=utf-8'
|
||
|
||
def json_error(err_msg):
|
||
result = {'error': [err_msg]}
|
||
return HttpResponseBadRequest(json.dumps(result),
|
||
content_type=content_type)
|
||
group_id = int(group_id)
|
||
group = get_group(group_id)
|
||
if not group:
|
||
return json_error(_(u'Failed to create: the group does not exist.'))
|
||
|
||
# Check whether user belongs to the group.
|
||
if not is_group_user(group_id, request.user.username):
|
||
return json_error(_(u'Failed to create: you are not in the group.'))
|
||
|
||
form = SharedRepoCreateForm(request.POST)
|
||
if not form.is_valid():
|
||
return json_error(form.errors)
|
||
else:
|
||
repo_name = form.cleaned_data['repo_name']
|
||
repo_desc = form.cleaned_data['repo_desc']
|
||
permission = form.cleaned_data['permission']
|
||
encrypted = form.cleaned_data['encryption']
|
||
passwd = form.cleaned_data['passwd']
|
||
user = request.user.username
|
||
|
||
org, base_template = check_and_get_org_by_group(group.id, user)
|
||
if org:
|
||
# create group repo in org context
|
||
try:
|
||
repo_id = create_org_repo(repo_name, repo_desc, user, passwd,
|
||
org.org_id)
|
||
except:
|
||
repo_id = None
|
||
if not repo_id:
|
||
return json_error(_(u'Failed to create'))
|
||
|
||
try:
|
||
status = seafserv_threaded_rpc.add_org_group_repo(repo_id,
|
||
org.org_id,
|
||
group.id,
|
||
user,
|
||
permission)
|
||
except SearpcError, e:
|
||
status = -1
|
||
|
||
# if share failed, remove the newly created repo
|
||
if status != 0:
|
||
remove_repo(repo_id)
|
||
return json_error(_(u'Failed to create: internal error.'))
|
||
else:
|
||
result = {'success': True}
|
||
return HttpResponse(json.dumps(result),
|
||
content_type=content_type)
|
||
else:
|
||
# create group repo in user context
|
||
repo_id = create_repo(repo_name, repo_desc, user, passwd)
|
||
if not repo_id:
|
||
return json_error(_(u'Failed to create'))
|
||
|
||
try:
|
||
status = seafserv_threaded_rpc.group_share_repo(repo_id,
|
||
group.id,
|
||
user,
|
||
permission)
|
||
except SearpcError, e:
|
||
status = -1
|
||
|
||
# if share failed, remove the newly created repo
|
||
if status != 0:
|
||
remove_repo(repo_id)
|
||
return json_error(_(u'Failed to create: internal error.'))
|
||
else:
|
||
result = {'success': True}
|
||
return HttpResponse(json.dumps(result),
|
||
content_type=content_type)
|
||
|
||
@login_required
|
||
def group_joinrequest(request, group_id):
|
||
"""
|
||
Handle post request to join a group.
|
||
"""
|
||
if not request.is_ajax() or request.method != 'POST':
|
||
raise Http404
|
||
|
||
result = {}
|
||
content_type = 'application/json; charset=utf-8'
|
||
|
||
group_id = int(group_id)
|
||
group = get_group(group_id)
|
||
if not group:
|
||
raise Http404
|
||
|
||
user = request.user.username
|
||
# TODO: Group creator is group staff now, but may changed in future.
|
||
staff = group.creator_name
|
||
if is_group_user(group_id, user):
|
||
# Already in the group. Normally, this case should not happen.
|
||
err = _(u'You are already in the group.')
|
||
return HttpResponseBadRequest(json.dumps({'error': err}),
|
||
content_type=content_type)
|
||
else:
|
||
form = GroupJoinMsgForm(request.POST)
|
||
if form.is_valid():
|
||
group_join_msg = form.cleaned_data['group_join_msg']
|
||
# Send the message to group staff.
|
||
use_https = request.is_secure()
|
||
domain = RequestSite(request).domain
|
||
t = loader.get_template('group/group_join_email.html')
|
||
c = {
|
||
'staff': staff,
|
||
'user': user,
|
||
'group_name': group.group_name,
|
||
'group_join_msg': group_join_msg,
|
||
'site_name': SITE_NAME,
|
||
}
|
||
try:
|
||
send_mail(_(u'apply to join the group'), t.render(Context(c)), None, [staff],
|
||
fail_silently=False)
|
||
messages.success(request, _(u'Sent successfully, the group admin will handle it.'))
|
||
return HttpResponse(json.dumps('success'),
|
||
content_type=content_type)
|
||
except:
|
||
err = _(u'Failed to send. You can try it again later.')
|
||
return HttpResponse(json.dumps({'error': err}), status=500,
|
||
content_type=content_type)
|
||
else:
|
||
return HttpResponseBadRequest(json.dumps(form.errors),
|
||
content_type=content_type)
|
||
|
||
def attention(request):
|
||
"""
|
||
Handle ajax request to query group members used in autocomplete.
|
||
"""
|
||
if not request.is_ajax():
|
||
raise Http404
|
||
|
||
user = request.user.username
|
||
name_str = request.GET.get('name_startsWith')
|
||
gids = request.GET.get('gids', '')
|
||
result = []
|
||
|
||
members = []
|
||
for gid in gids.split('_'):
|
||
try:
|
||
gid = int(gid)
|
||
except ValueError:
|
||
continue
|
||
|
||
if not is_group_user(gid, user):
|
||
continue
|
||
|
||
# Get all group users
|
||
members += get_group_members(gid)
|
||
|
||
member_names = []
|
||
for m in members:
|
||
if len(result) == 10: # Return at most 10 results.
|
||
break
|
||
|
||
if m.user_name == user:
|
||
continue
|
||
|
||
if m.user_name in member_names:
|
||
# Remove duplicated member names
|
||
continue
|
||
else:
|
||
member_names.append(m.user_name)
|
||
|
||
from base.templatetags.seahub_tags import email2nickname, char2pinyin
|
||
nickname = email2nickname(m.user_name)
|
||
pinyin = char2pinyin(nickname)
|
||
if nickname.startswith(name_str) or pinyin.startswith(name_str):
|
||
result.append({'contact_name': nickname})
|
||
|
||
content_type = 'application/json; charset=utf-8'
|
||
|
||
return HttpResponse(json.dumps(result), content_type=content_type)
|
||
|
||
|
||
@group_check
|
||
def group_discuss(request, group):
|
||
username = request.user.username
|
||
if request.method == 'POST':
|
||
# only login user can post to public group
|
||
if group.view_perm == "pub" and not request.user.is_authenticated():
|
||
raise Http404
|
||
|
||
form = MessageForm(request.POST)
|
||
|
||
if form.is_valid():
|
||
msg = form.cleaned_data['message']
|
||
message = GroupMessage()
|
||
message.group_id = group.id
|
||
message.from_email = request.user.username
|
||
message.message = msg
|
||
message.save()
|
||
|
||
# send signal
|
||
grpmsg_added.send(sender=GroupMessage, group_id=group.id,
|
||
from_email=username)
|
||
# Always return an HttpResponseRedirect after successfully dealing
|
||
# with POST data.
|
||
return HttpResponseRedirect(reverse('group_discuss', args=[group.id]))
|
||
else:
|
||
form = MessageForm()
|
||
|
||
# remove user notifications
|
||
UserNotification.objects.filter(to_user=username, msg_type='group_msg',
|
||
detail=str(group.id)).delete()
|
||
|
||
# Get all group members.
|
||
members = get_group_members(group.id)
|
||
|
||
"""group messages"""
|
||
# Show 15 group messages per page.
|
||
paginator = Paginator(GroupMessage.objects.filter(
|
||
group_id=group.id).order_by('-timestamp'), 15)
|
||
|
||
# Make sure page request is an int. If not, deliver first page.
|
||
try:
|
||
page = int(request.GET.get('page', '1'))
|
||
except ValueError:
|
||
page = 1
|
||
|
||
# If page request (9999) is out of range, deliver last page of results.
|
||
try:
|
||
group_msgs = paginator.page(page)
|
||
except (EmptyPage, InvalidPage):
|
||
group_msgs = paginator.page(paginator.num_pages)
|
||
|
||
group_msgs.page_range = paginator.get_page_range(group_msgs.number)
|
||
|
||
# Force evaluate queryset to fix some database error for mysql.
|
||
group_msgs.object_list = list(group_msgs.object_list)
|
||
|
||
attachments = MessageAttachment.objects.filter(group_message__in=group_msgs.object_list)
|
||
|
||
msg_replies = MessageReply.objects.filter(reply_to__in=group_msgs.object_list)
|
||
reply_to_list = [ r.reply_to_id for r in msg_replies ]
|
||
|
||
for msg in group_msgs.object_list:
|
||
msg.reply_cnt = reply_to_list.count(msg.id)
|
||
msg.replies = []
|
||
for r in msg_replies:
|
||
if msg.id == r.reply_to_id:
|
||
msg.replies.append(r)
|
||
msg.replies = msg.replies[-3:]
|
||
|
||
for att in attachments:
|
||
if att.group_message_id != msg.id:
|
||
continue
|
||
|
||
# Attachment name is file name or directory name.
|
||
# If is top directory, use repo name instead.
|
||
path = att.path
|
||
if path == '/':
|
||
repo = get_repo(att.repo_id)
|
||
if not repo:
|
||
# TODO: what should we do here, tell user the repo
|
||
# is no longer exists?
|
||
continue
|
||
att.name = repo.name
|
||
else:
|
||
path = path.rstrip('/') # cut out last '/' if possible
|
||
att.name = os.path.basename(path)
|
||
|
||
# Load to discuss page if attachment is a image and from recommend.
|
||
if att.attach_type == 'file' and att.src == 'recommend':
|
||
att.filetype, att.fileext = get_file_type_and_ext(att.name)
|
||
if att.filetype == IMAGE:
|
||
att.obj_id = get_file_id_by_path(att.repo_id, path)
|
||
if not att.obj_id:
|
||
att.err = _(u'File does not exist')
|
||
else:
|
||
att.token = web_get_access_token(att.repo_id, att.obj_id,
|
||
'view', username)
|
||
att.img_url = gen_file_get_url(att.token, att.name)
|
||
|
||
msg.attachment = att
|
||
|
||
return render_to_response("group/group_discuss.html", {
|
||
"members": members,
|
||
"group" : group,
|
||
"is_staff": group.is_staff,
|
||
"group_msgs": group_msgs,
|
||
"form": form,
|
||
'group_members_default_display': GROUP_MEMBERS_DEFAULT_DISPLAY,
|
||
}, context_instance=RequestContext(request))
|
||
|
||
|
||
class WikiDoesNotExist(Exception):
|
||
pass
|
||
|
||
class WikiPageMissing(Exception):
|
||
pass
|
||
|
||
def find_wiki_repo(request, group):
|
||
try:
|
||
groupwiki = GroupWiki.objects.get(group_id=group.id)
|
||
repos = get_group_repos(group.id, request.user.username)
|
||
for repo in repos:
|
||
if repo.id == groupwiki.repo_id:
|
||
return repo
|
||
return None
|
||
except GroupWiki.DoesNotExist:
|
||
return None
|
||
|
||
def get_file_url(repo, obj_id, file_name):
|
||
repo_id = repo.id
|
||
access_token = seafserv_rpc.web_get_access_token(repo_id, obj_id,
|
||
'view', '')
|
||
url = gen_file_get_url(access_token, file_name)
|
||
return url
|
||
|
||
def get_wiki_page(request, group, page_name):
|
||
repo = find_wiki_repo(request, group)
|
||
if not repo:
|
||
raise WikiDoesNotExist
|
||
dirent = get_wiki_dirent(repo.id, page_name)
|
||
if not dirent:
|
||
raise WikiPageMissing
|
||
url = get_file_url(repo, dirent.obj_id, dirent.obj_name)
|
||
file_response = urllib2.urlopen(url)
|
||
content = file_response.read()
|
||
return content, repo.id, dirent
|
||
|
||
def convert_wiki_link(content, group, repo_id, username):
|
||
import re
|
||
|
||
def repl(matchobj):
|
||
if matchobj.group(2): # return origin string in backquotes
|
||
return matchobj.group(2)
|
||
|
||
page_name = matchobj.group(1).strip()
|
||
filetype, fileext = get_file_type_and_ext(page_name)
|
||
if fileext == '':
|
||
# convert page_name that extension is missing to a markdown page
|
||
page_alias = page_name
|
||
if len(page_name.split('|')) > 1:
|
||
page_alias = page_name.split('|')[0]
|
||
page_name = page_name.split('|')[1]
|
||
dirent = get_wiki_dirent(repo_id, page_name)
|
||
if dirent is not None:
|
||
a_tag = "<a href='%s'>%s</a>"
|
||
return a_tag % (reverse('group_wiki', args=[group.id, normalize_page_name(page_name)]), page_alias)
|
||
else:
|
||
a_tag = '''<a class="wiki-page-missing" href='%s'>%s</a>'''
|
||
return a_tag % (reverse('group_wiki', args=[group.id, page_name.replace('/', '-')]), page_alias)
|
||
elif filetype == IMAGE:
|
||
# load image to wiki page
|
||
path = "/" + page_name
|
||
filename = os.path.basename(path)
|
||
obj_id = get_file_id_by_path(repo_id, path)
|
||
if not obj_id:
|
||
# Replace '/' in page_name to '-', since wiki name can not
|
||
# contain '/'.
|
||
return '''<a class="wiki-page-missing" href='%s'>%s</a>''' % \
|
||
(reverse('group_wiki', args=[group.id, page_name.replace('/', '-')]), page_name)
|
||
|
||
token = web_get_access_token(repo_id, obj_id, 'view', username)
|
||
return '<img src="%s" alt="%s" />' % (gen_file_get_url(token, filename), filename)
|
||
else:
|
||
from base.templatetags.seahub_tags import file_icon_filter
|
||
|
||
# convert other types of filelinks to clickable links
|
||
path = "/" + page_name
|
||
icon = file_icon_filter(page_name)
|
||
s = reverse('repo_view_file', args=[repo_id]) + \
|
||
'?p=' + urllib2.quote(smart_str(path))
|
||
a_tag = '''<img src="%simg/file/%s" alt="%s" class="vam" /> <a href='%s' target='_blank' class="vam">%s</a>'''
|
||
return a_tag % (MEDIA_URL, icon, icon, s, page_name)
|
||
|
||
return re.sub(r'\[\[(.+)\]\]|(`.+`)', repl, content)
|
||
|
||
|
||
@group_check
|
||
def group_wiki(request, group, page_name="home"):
|
||
username = request.user.username
|
||
wiki_exists = True
|
||
try:
|
||
content, repo_id, dirent = get_wiki_page(request, group, page_name)
|
||
except WikiDoesNotExist:
|
||
wiki_exists = False
|
||
return render_to_response("group/group_wiki.html", {
|
||
"group" : group,
|
||
"is_staff": group.is_staff,
|
||
"wiki_exists": wiki_exists,
|
||
}, context_instance=RequestContext(request))
|
||
except WikiPageMissing:
|
||
'''create that page for user if he/she is a group member'''
|
||
if not is_group_user(group.id, username):
|
||
raise Http404
|
||
|
||
repo = find_wiki_repo(request, group)
|
||
# No need to check whether repo is none, since repo is already created
|
||
|
||
filename = clean_page_name(page_name) + '.md'
|
||
if not post_empty_file(repo.id, "/", filename, username):
|
||
return render_error(request, _("Failed to create wiki page. Please retry later."))
|
||
return HttpResponseRedirect(reverse('group_wiki', args=[group.id, page_name]))
|
||
else:
|
||
content = convert_wiki_link(content, group, repo_id, username)
|
||
|
||
# fetch file latest contributor and last modified
|
||
path = '/' + dirent.obj_name
|
||
file_path_hash = md5_constructor(urllib2.quote(path.encode('utf-8'))).hexdigest()[:12]
|
||
contributors, last_modified, last_commit_id = get_file_contributors(\
|
||
repo_id, path.encode('utf-8'), file_path_hash, dirent.obj_id)
|
||
latest_contributor = contributors[0] if contributors else None
|
||
|
||
return render_to_response("group/group_wiki.html", {
|
||
"group" : group,
|
||
"is_staff": group.is_staff,
|
||
"wiki_exists": wiki_exists,
|
||
"content": content,
|
||
"page": os.path.splitext(dirent.obj_name)[0],
|
||
"last_modified": last_modified,
|
||
"latest_contributor": latest_contributor,
|
||
"path": path,
|
||
"repo_id": repo_id,
|
||
}, context_instance=RequestContext(request))
|
||
|
||
@group_check
|
||
def group_wiki_pages(request, group):
|
||
"""
|
||
List wiki pages in group.
|
||
"""
|
||
repo = find_wiki_repo(request, group)
|
||
if not repo:
|
||
return render_error(request, _('Wiki is not found.'))
|
||
|
||
try:
|
||
dir_id = seafserv_threaded_rpc.get_dir_id_by_path(repo.id, '/')
|
||
except SearpcError, e:
|
||
dir_id = None
|
||
if not dir_id:
|
||
return render_error(request, _('Wiki root path is missing.'))
|
||
|
||
try:
|
||
dirs = seafserv_threaded_rpc.list_dir(dir_id)
|
||
except SearpcError, e:
|
||
return render_error(request, _('Failed to list wiki directories.'))
|
||
|
||
pages = {}
|
||
for e in dirs:
|
||
if stat.S_ISDIR(e.mode):
|
||
continue # skip directories
|
||
name, ext = os.path.splitext(e.obj_name)
|
||
if ext == '.md':
|
||
key = normalize_page_name(name)
|
||
pages[key] = name
|
||
|
||
return render_to_response("group/group_wiki_pages.html", {
|
||
"group": group,
|
||
"pages": pages,
|
||
"is_staff": group.is_staff,
|
||
"repo_id": repo.id
|
||
}, context_instance=RequestContext(request))
|
||
|
||
|
||
@group_check
|
||
def group_wiki_create(request, group):
|
||
if group.view_perm == "pub":
|
||
raise Http404
|
||
|
||
if request.method != 'POST':
|
||
raise Http404
|
||
|
||
content_type = 'application/json; charset=utf-8'
|
||
|
||
def json_error(err_msg, status=400):
|
||
result = {'error': err_msg}
|
||
return HttpResponse(json.dumps(result), status=status,
|
||
content_type=content_type)
|
||
|
||
form = WikiCreateForm(request.POST)
|
||
if not form.is_valid():
|
||
return json_error(str(form.errors.values()[0]))
|
||
|
||
# create group repo in user context
|
||
repo_name = form.cleaned_data['repo_name']
|
||
repo_desc = form.cleaned_data['repo_desc']
|
||
user = request.user.username
|
||
passwd = None
|
||
permission = "rw"
|
||
|
||
repo_id = create_repo(repo_name, repo_desc, user, passwd)
|
||
if not repo_id:
|
||
return json_error(_(u'Failed to create'), 500)
|
||
|
||
try:
|
||
status = seafserv_threaded_rpc.group_share_repo(repo_id,
|
||
group.id,
|
||
user,
|
||
permission)
|
||
except SearpcError, e:
|
||
remove_repo(repo_id)
|
||
return json_error(_(u'Failed to create: internal error.'), 500)
|
||
|
||
GroupWiki.objects.save_group_wiki(group_id=group.id, repo_id=repo_id)
|
||
|
||
# create home page
|
||
page_name = "home.md"
|
||
if not post_empty_file(repo_id, "/", page_name, user):
|
||
return json_error(_(u'Failed to create home page. Please retry later'), 500)
|
||
|
||
next = reverse('group_wiki', args=[group.id])
|
||
return HttpResponse(json.dumps({'href': next}), content_type=content_type)
|
||
|
||
@group_check
|
||
def group_wiki_page_new(request, group, page_name="home"):
|
||
if group.view_perm == "pub":
|
||
raise Http404
|
||
|
||
if request.method == 'POST':
|
||
form = MessageForm(request.POST)
|
||
|
||
page_name = request.POST.get('page_name', '')
|
||
if not page_name:
|
||
return HttpResponseRedirect(request.META.get('HTTP_REFERER'))
|
||
page_name = clean_page_name(page_name)
|
||
|
||
repo = find_wiki_repo(request, group)
|
||
if not repo:
|
||
return render_error(request, _('Wiki is not found.'))
|
||
|
||
filename = page_name + ".md"
|
||
filepath = "/" + page_name + ".md"
|
||
|
||
# check whether file exists
|
||
if get_file_id_by_path(repo.id, filepath):
|
||
return render_error(request, _('Page "%s" already exists.') % filename)
|
||
|
||
if not post_empty_file(repo.id, "/", filename, request.user.username):
|
||
return render_error(request, _('Failed to create wiki page. Please retry later.'))
|
||
|
||
url = "%s?p=%s&from=wiki_page_new&gid=%s" % (
|
||
reverse('file_edit', args=[repo.id]),
|
||
urllib2.quote(filepath.encode('utf-8')), group.id)
|
||
return HttpResponseRedirect(url)
|
||
|
||
|
||
@group_check
|
||
def group_wiki_page_edit(request, group, page_name="home"):
|
||
if group.view_perm == "pub":
|
||
raise Http404
|
||
|
||
repo = find_wiki_repo(request, group)
|
||
if not repo:
|
||
return render_error(request, _('Wiki is not found.'))
|
||
|
||
filepath = "/" + page_name + ".md"
|
||
url = "%s?p=%s&from=wiki_page_edit&gid=%s" % (
|
||
reverse('file_edit', args=[repo.id]),
|
||
urllib2.quote(filepath.encode('utf-8')), group.id)
|
||
|
||
return HttpResponseRedirect(url)
|
||
|
||
|
||
@group_check
|
||
def group_wiki_page_delete(request, group, page_name):
|
||
if group.view_perm == "pub":
|
||
raise Http404
|
||
|
||
repo = find_wiki_repo(request, group)
|
||
if not repo:
|
||
return render_error(request, _('Wiki is not found.'))
|
||
|
||
file_name = page_name + '.md'
|
||
user = request.user.username
|
||
if del_file(repo.id, '/', file_name, user):
|
||
messages.success(request, 'Successfully deleted "%s".' % page_name)
|
||
else:
|
||
messages.error(request, 'Failed to delete "%s". Please retry later.' % page_name)
|
||
|
||
return HttpResponseRedirect(reverse('group_wiki', args=[group.id]))
|
||
|