From d63b068b2de37a62e355879eddf60ff4fa733dac Mon Sep 17 00:00:00 2001 From: xiez Date: Tue, 15 May 2012 10:59:16 +0800 Subject: [PATCH] Add group feature --- base/templatetags/seahub_tags.py | 6 +- group/models.py | 32 +-- group/templates/group/group_info.html | 118 +++++++++++ group/templates/group/groups.html | 49 +++++ group/tests.py | 23 +++ group/urls.py | 15 ++ group/views.py | 153 ++++++++++++++- settings.py | 2 +- templates/error.html | 8 + templates/groups.html | 33 ---- templates/myhome.html | 6 +- templates/myhome_base.html | 4 +- templates/permission_error.html | 4 +- templates/share_repos.html | 2 +- thirdpart/seaserv/__init__.py | 1 + thirdpart/seaserv/service.py | 22 +++ urls.py | 5 +- utils.py | 73 +++++++ views.py | 270 ++++++++++++++------------ 19 files changed, 631 insertions(+), 195 deletions(-) create mode 100644 group/templates/group/group_info.html create mode 100644 group/templates/group/groups.html create mode 100644 group/tests.py create mode 100644 group/urls.py create mode 100644 templates/error.html delete mode 100644 templates/groups.html create mode 100644 utils.py diff --git a/base/templatetags/seahub_tags.py b/base/templatetags/seahub_tags.py index 52e77eef1a..922727e43c 100644 --- a/base/templatetags/seahub_tags.py +++ b/base/templatetags/seahub_tags.py @@ -6,4 +6,8 @@ register = template.Library() @register.filter(name='tsstr_sec') def tsstr_sec(value): """Turn a timestamp to string""" - return datetime.fromtimestamp(value).strftime("%Y-%m-%d %H:%M:%S") + try: + return datetime.fromtimestamp(value).strftime("%Y-%m-%d %H:%M:%S") + except: + return datetime.fromtimestamp(value/1000000).strftime("%Y-%m-%d %H:%M:%S") + diff --git a/group/models.py b/group/models.py index 6823f71807..71a8362390 100644 --- a/group/models.py +++ b/group/models.py @@ -1,33 +1,3 @@ from django.db import models -from django.contrib.auth.models import User -from django.utils.translation import ugettext_lazy as _ - -class Group(models.Model): - """A group is identified uniquely by group_id.""" - - group_id = models.CharField(max_length=36, primary_key=True, db_column='uuid') - name = models.CharField(max_length=20, editable=False, unique=True) - creator = models.ForeignKey(User, verbose_name=_("creator"), related_name="%(class)s_created") - admin = models.ForeignKey(User, verbose_name=_("admin"), related_name="%(class)s_admined") - ctime = models.DateTimeField('create time', editable=False) - description = models.TextField(_("description")) - users = models.ManyToManyField(User) - - def __unicode__(self): - return self.name - - -class JoinRequest(models.Model): - """A request for joining a group.""" - group = models.ForeignKey(Group) - user = models.ForeignKey(User) - ctime = models.DateTimeField('create time', editable=False) - - -class Invitation(models.Model): - """An invitation for joining a group.""" - - group = models.ForeignKey(Group) - user = models.ForeignKey(User) - ctime = models.DateTimeField('create time', editable=False) +# Create your models here. diff --git a/group/templates/group/group_info.html b/group/templates/group/group_info.html new file mode 100644 index 0000000000..c6936d2bb4 --- /dev/null +++ b/group/templates/group/group_info.html @@ -0,0 +1,118 @@ +{% extends "myhome_base.html" %} +{% load seahub_tags %} + +{% block nav_group_class %}class="cur"{% endblock %} +{% block left_panel %} + +{% endblock %} + +{% block right_panel %} + +

小组里共享的同步目录

+{% if repos %} + + + + + + + + + {% for repo in repos %} + + + + + + + {% endfor %} +
名字描述共享来源操作
{{ repo.props.name }}{{ repo.props.desc }}{{ repo.share_from }} + + {% if is_creator or repo.share_from_me %} + + {% endif %} +
+{% else %} +

暂无

+{% endif %} + +
+
+ + + +
+
+
+ + + +
+ +
+

确定要解散?

+ + +
+ +
+

确定要退出?

+ + +
+ +{% endblock %} + +{% block extra_script %} + +{% endblock %} diff --git a/group/templates/group/groups.html b/group/templates/group/groups.html new file mode 100644 index 0000000000..300f03c21b --- /dev/null +++ b/group/templates/group/groups.html @@ -0,0 +1,49 @@ +{% extends "myhome_base.html" %} +{% load seahub_tags %} + +{% block nav_group_class %}class="cur"{% endblock %} +{% block left_panel %} + +{% endblock %} + +{% block right_panel %} + +

我参加的小组

+{% if groups %} + + + + + + + + {% for group in groups %} + + + + + + {% endfor %} +
名字创建者创建时间
{{ group.props.group_name }}{{ group.props.creator_name }}{{ group.props.timestamp|tsstr_sec }}
+{% else %} +

暂无

+{% endif %} + +
+
+ + +
+ +{% endblock %} + +{% block extra_script %} + +{% endblock %} diff --git a/group/tests.py b/group/tests.py new file mode 100644 index 0000000000..2247054b35 --- /dev/null +++ b/group/tests.py @@ -0,0 +1,23 @@ +""" +This file demonstrates two different styles of tests (one doctest and one +unittest). These will both pass when you run "manage.py test". + +Replace these with more appropriate tests for your application. +""" + +from django.test import TestCase + +class SimpleTest(TestCase): + def test_basic_addition(self): + """ + Tests that 1 + 1 always equals 2. + """ + self.failUnlessEqual(1 + 1, 2) + +__test__ = {"doctest": """ +Another way to test that 1 + 1 is equal to 2. + +>>> 1 + 1 == 2 +True +"""} + diff --git a/group/urls.py b/group/urls.py new file mode 100644 index 0000000000..d6645bc236 --- /dev/null +++ b/group/urls.py @@ -0,0 +1,15 @@ +from django.conf.urls.defaults import * + +from views import group_list, group_add, group_info, \ + group_add_member, group_remove_member, \ + group_quit, group_remove + +urlpatterns = patterns('', + url(r'^$', group_list, name='group_list'), + (r'^add/$', group_add), + (r'^rm/$', group_remove), + (r'^memberadd/$', group_add_member), + (r'^memberrm/$', group_remove_member), + (r'^quit/$', group_quit), + url(r'^(?P[^/]+)/$', group_info, name='group_info'), +) diff --git a/group/views.py b/group/views.py index 65f283ad74..9faf2034cb 100644 --- a/group/views.py +++ b/group/views.py @@ -1,4 +1,153 @@ +# encoding: utf-8 -from django.contrib.auth.decorators import login_required -from django.contrib.auth.models import User +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 seaserv import ccnet_rpc, seafserv_threaded_rpc, get_repo, \ + get_group_repoids + +from seahub.views import validate_emailuser +from seahub.utils import go_error, go_permission_error + +from pysearpc import SearpcError + +@login_required +def group_list(request): + groups = ccnet_rpc.get_groups(request.user.username); + + return render_to_response("group/groups.html", { + "groups": groups, + }, context_instance=RequestContext(request)) + +@login_required +def group_add(request): + error_msg = None + if request.method == 'POST': + group_name = request.POST.get('group_name') + if group_name.find('@') >= 0: + return go_error(request, u'小组名称不能包含@') + + try: + ccnet_rpc.create_group(group_name.encode('utf-8'), request.user.username) + except SearpcError, e: + error_msg = e.msg + return go_error(request, error_msg) + + return HttpResponseRedirect(reverse('group_list', args=[])) + +@login_required +def group_remove(request): + group_id = request.GET.get('gid') + + try: + group_id_int = int(group_id) + except ValueError: + group_id_int = -1 + + try: + ccnet_rpc.remove_group(group_id_int, request.user.username) + seafserv_threaded_rpc.remove_repo_group(group_id_int, None) + except SearpcError, e: + return go_error(request, e.msg) + + return HttpResponseRedirect(reverse('group_list', args=[])) + +@login_required +def group_info(request, group_id): + try: + group_id_int = int(group_id) + except ValueError: + return HttpResponseRedirect(reverse('group_list', args=[])) + + group = ccnet_rpc.get_group(group_id_int) + if not group: + return HttpResponseRedirect(reverse('group_list', args=[])) + + if group.props.creator_name == request.user.username: + is_creator = True + else: + is_creator = False + + members = ccnet_rpc.get_group_members(group_id_int) + + repos = [] + repo_ids = get_group_repoids(group_id=group_id_int) + for repo_id in repo_ids: + if not repo_id: + continue + repo = get_repo(repo_id) + repo.share_from = seafserv_threaded_rpc.get_group_repo_share_from(repo_id) + if request.user.username == repo.share_from: + repo.share_from_me = True + else: + repo.share_from_me = False + repos.append(repo) + + return render_to_response("group/group_info.html", { + "members": members, + "repos": repos, + "group_id": group_id, + "is_creator": is_creator, + }, context_instance=RequestContext(request)); + +@login_required +def group_add_member(request): + if request.method == 'POST': + group_id = request.POST.get('group_id') + member_name = request.POST.get('user_name') + if not validate_emailuser(member_name): + err_msg = u'用户不存在' + return go_error(request, err_msg) + else: + try: + group_id_int = int(group_id) + except ValueError: + return go_error(request, u'group id 不是有效参数') + try: + ccnet_rpc.group_add_member(group_id_int, request.user.username, + member_name) + except SearpcError, e: + return go_error(request, e.msg) + + return HttpResponseRedirect(reverse('group_info', args=[group_id])) + +@login_required +def group_remove_member(request): + if request.method == 'POST': + group_id = request.POST.get('group_id') + member_name = request.POST.get('user_name') + if not validate_emailuser(member_name): + err_msg = u'用户不存在' + return go_error(request, err_msg) + else: + try: + group_id_int = int(group_id) + except ValueError: + raise Http404 + try: + ccnet_rpc.group_remove_member(group_id_int, request.user.username, + member_name) + seafserv_threaded_rpc.remove_repo_group(group_id_int, member_name) + except SearpcError, e: + return go_error(request, e.msg) + + return HttpResponseRedirect(reverse('group_info', args=[group_id])) + +@login_required +def group_quit(request): + group_id = request.GET.get('gid') + try: + group_id_int = int(group_id) + except ValueError: + raise Http404 + + try: + ccnet_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 go_error(request, e.msg) + + return HttpResponseRedirect(reverse('group_list', args=[])) diff --git a/settings.py b/settings.py index e15e83e73b..aade832304 100644 --- a/settings.py +++ b/settings.py @@ -103,7 +103,7 @@ INSTALLED_APPS = ( 'seahub.base', 'seahub.profile', 'seahub.contacts', -# 'seahub.group', + 'seahub.group', # 'seahub.share', ) diff --git a/templates/error.html b/templates/error.html new file mode 100644 index 0000000000..761ad3cc21 --- /dev/null +++ b/templates/error.html @@ -0,0 +1,8 @@ +{% extends "myhome_base.html" %} + +{% block title %}错误{% endblock %} + +{% block main_panel %} + +

{{ error_msg }}

+{% endblock %} diff --git a/templates/groups.html b/templates/groups.html deleted file mode 100644 index b2931319cf..0000000000 --- a/templates/groups.html +++ /dev/null @@ -1,33 +0,0 @@ -{% extends "base.html" %} - -{% block title %}Groups{% endblock %} - -{% block left_panel %} - -{% endblock %} - -{% block right_panel %} - -

Use the following command to add a group:

-
ccnet-tool group-follow <group-id> <rendevous-id>
- -

Groups

- - - - - - - - - {% for group in groups %} - - - - - - - {% endfor %} -
NameIDRendezvousMaintainer
{{ group.props.name }}{{ group.props.id }}{{ group.props.rendezvous }}{{ group.props.maintainers }}
- -{% endblock %} diff --git a/templates/myhome.html b/templates/myhome.html index 443e8b8f7c..b693578648 100644 --- a/templates/myhome.html +++ b/templates/myhome.html @@ -70,7 +70,7 @@ {% endif %}
-
+

输入不能为空。

@@ -88,6 +88,10 @@ $(function() { contact_list.push('{{ contact.contact_email }}'); {% endfor %} + {% for group in groups %} + contact_list.push('{{ group.props.group_name }} <{{ group.props.creator_name }}>'); + {% endfor %} + function split(val) { return val.split(/,\s*/); } diff --git a/templates/myhome_base.html b/templates/myhome_base.html index 9dab70e46c..14ecce8e9f 100644 --- a/templates/myhome_base.html +++ b/templates/myhome_base.html @@ -10,7 +10,9 @@
  • 联系人
  • - +
  • + 小组 +
  • {% if request.user.is_staff %}
  • 目录管理 diff --git a/templates/permission_error.html b/templates/permission_error.html index 5a3d7f6777..8f62e28fe3 100644 --- a/templates/permission_error.html +++ b/templates/permission_error.html @@ -1,8 +1,8 @@ {% extends "myhome_base.html" %} -{% block title %}Permission Error{% endblock %} +{% block title %}权限错误{% endblock %} {% block main_panel %} -

    Permission Error.

    +

    {{ error_msg }}

    {% endblock %} diff --git a/templates/share_repos.html b/templates/share_repos.html index c48defe1ce..0002c647d5 100644 --- a/templates/share_repos.html +++ b/templates/share_repos.html @@ -18,7 +18,7 @@ {{ repo.props.shared_email }} {{ repo.props.desc }} - + {% endfor %} diff --git a/thirdpart/seaserv/__init__.py b/thirdpart/seaserv/__init__.py index 41e4bd1fc3..9feab701ad 100644 --- a/thirdpart/seaserv/__init__.py +++ b/thirdpart/seaserv/__init__.py @@ -12,6 +12,7 @@ from service import get_users, get_user, get_events, count_event from service import get_repos, get_repo, get_commits, get_branches from service import get_binding_peerids from service import get_ccnetuser +from service import get_group_repoids from service import CCNET_CONF_PATH diff --git a/thirdpart/seaserv/service.py b/thirdpart/seaserv/service.py index 63904c27bc..9bc6be7fbe 100644 --- a/thirdpart/seaserv/service.py +++ b/thirdpart/seaserv/service.py @@ -385,9 +385,31 @@ def get_binding_peerids(email): except SearpcError: return [] + if not peer_ids: + return [] + peerid_list = [] for peer_id in peer_ids.split("\n"): if peer_id == '': continue peerid_list.append(peer_id) return peerid_list + +def get_group_repoids(group_id=None): + """Get repo ids of a given group id or username""" + try: + repo_ids = seafserv_threaded_rpc.get_group_repoids(group_id) + except SearpcError: + return [] + + if not repo_ids: + return [] + + repoid_list = [] + for repo_id in repo_ids.split("\n"): + if repo_id == '': + continue + repoid_list.append(repo_id) + return repoid_list + + diff --git a/urls.py b/urls.py index 487432d73a..d0e6783a0e 100644 --- a/urls.py +++ b/urls.py @@ -2,8 +2,8 @@ from django.conf.urls.defaults import * from django.conf import settings from django.views.generic.simple import direct_to_template -from seahub.views import root, peers, groups, myhome, \ - repo, repo_history, group, modify_token, remove_repo, seafadmin, useradmin, \ +from seahub.views import root, peers, myhome, \ + repo, repo_history, modify_token, remove_repo, seafadmin, useradmin, \ role_add, role_remove, activate_user, user_add, user_remove, \ ownerhome, remove_fetched_repo, \ repo_list_dir, user_info, repo_set_access_property, repo_operation_file, \ @@ -54,6 +54,7 @@ urlpatterns = patterns('', (r'^useradmin/(?P[^/]+)/user/remove/$', user_remove), (r'^useradmin/activate/(?P[^/]+)/$', activate_user), # (r'^avatar/', include('avatar.urls')), + (r'^group/', include('seahub.group.urls')), (r'^profile/', include('seahub.profile.urls')), (r'^back/local/$', back_local), diff --git a/utils.py b/utils.py new file mode 100644 index 0000000000..e0bca431ce --- /dev/null +++ b/utils.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python +# encoding: utf-8 + +from django.shortcuts import render_to_response +from django.template import RequestContext + +from django.utils.hashcompat import sha_constructor + +import time +import settings + +def go_permission_error(request, msg=None): + """ + return permisson error page + + """ + return render_to_response('permission_error.html', { + 'error_msg': msg or u'权限错误', + }, context_instance=RequestContext(request)) + +def go_error(request, msg=None): + """ + return normal error page + + """ + return render_to_response('error.html', { + 'error_msg': msg or u'内部错误', + }, context_instance=RequestContext(request)) + +def list_to_string(l): + """ + return string of a list + + """ + 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 + + """ + + token = sha_constructor(settings.SECRET_KEY + unicode(time.time())).hexdigest()[::8] + return token diff --git a/views.py b/views.py index e2320fbf00..f2dc80116b 100644 --- a/views.py +++ b/views.py @@ -1,4 +1,5 @@ # encoding: utf-8 + from django.http import HttpResponse, HttpResponseRedirect, Http404 from django.shortcuts import render_to_response, redirect from django.core.urlresolvers import reverse @@ -6,13 +7,15 @@ 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.forms import AuthenticationForm, PasswordResetForm, SetPasswordForm, \ + PasswordChangeForm from auth.tokens import default_token_generator from pysearpc import SearpcError from seaserv import ccnet_rpc, get_groups, get_users, get_repos, \ get_repo, get_commits, get_branches, \ - seafserv_threaded_rpc, seafserv_rpc, get_binding_peerids, get_ccnetuser + seafserv_threaded_rpc, seafserv_rpc, get_binding_peerids, get_ccnetuser, \ + get_group_repoids from seahub.share.models import GroupShare, UserShare from seahub.share.forms import GroupAddRepoForm @@ -22,43 +25,62 @@ from urllib import quote from seahub.contacts.models import Contact +from utils import go_permission_error, go_error, list_to_string, get_httpserver_root, \ + get_ccnetapplet_root, gen_token + 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 group_share_repo(request, repo_id, group_id, from_email): + """ + share a repo to a group + """ + # check whether group exists + group = ccnet_rpc.get_group(group_id) + if not group: + return go_error(request, u'共享失败:小组不存在') -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 + # check whether user belong to the group + joined = False + groups = ccnet_rpc.get_groups(request.user.username) + for group in groups: + if group.props.id == group_id: + joined = True + if not joined: + return go_error(request, u'共享失败:未加入该小组') + + if seafserv_threaded_rpc.group_share_repo(repo_id, group_id, from_email) != 0: + return go_error(request, u'共享失败:内部错误') +def group_unshare_repo(request, repo_id, group_id, from_email): + """ + unshare a repo to a group + + """ + # check whether group exists + group = ccnet_rpc.get_group(group_id) + if not group: + return go_error(request, u'共享失败:小组不存在') + + # check whether user belong to the group + joined = False + groups = ccnet_rpc.get_groups(from_email) + for group in groups: + if group.props.id == group_id: + joined = True + if not joined: + return go_error(request, u'共享失败:未加入该小组') + + # check whether user is group staff or the one share the repo + if not ccnet_rpc.check_group_staff(group_id, from_email) and \ + seafserv_threaded_rpc.get_group_repo_share_from(repo_id) != from_email: + return go_permission_error(request, u'取消共享失败:只有小组管理员或共享目录发布者有权取消共享') + + if seafserv_threaded_rpc.group_unshare_repo(repo_id, group_id, from_email) != 0: + return go_error(request, u'共享失败:内部错误') + @login_required def root(request): return HttpResponseRedirect(reverse(myhome)) @@ -84,75 +106,27 @@ def peers(request): '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) + """ + check whether user has been shared this repo or + the repo share to the groups user join + """ + 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: + if repo.props.id == repo_id: + return True + + groups = ccnet_rpc.get_groups(request.user.username) + # for every group that user joined... + for group in groups: + # ...get repo ids in that group, and check whether repo ids contains that repo id + repo_ids = get_group_repoids(group.props.id) + if repo_ids.__contains__(repo_id): return True return False @@ -210,11 +184,13 @@ def repo(request, repo_id): 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 a repo is shared to me, or repo shared to the group I joined, + # 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, @@ -256,15 +232,6 @@ def repo_history(request, repo_id): }, 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): @@ -280,9 +247,8 @@ def modify_token(request, 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)) - + return go_permission_error(request, u'权限不足:无法查看该用户信息') + seafserv_threaded_rpc.remove_repo(repo_id) return HttpResponseRedirect(request.META['HTTP_REFERER']) @@ -305,18 +271,24 @@ def myhome(request): # Repos that are share to me in_repos = seafserv_threaded_rpc.list_share_repos(request.user.username, 'to_email', -1, -1) - + + # handle share repo request if request.method == 'POST': output_msg = repo_add_share(request) + # my contacts contacts = Contact.objects.filter(user_email=email) - + + # groups I join + groups = ccnet_rpc.get_groups(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, + "groups": groups, }, context_instance=RequestContext(request)) @login_required @@ -426,7 +398,13 @@ def repo_add_share(request): 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(',') + + # Handle the diffent separator + to_email_str = request.POST.get('to_email', '').replace(';',',') + to_email_str = to_email_str.replace('\n',',') + to_email_str = to_email_str.replace('\r',',') + + to_email_list = to_email_str.split(',') info_emails = [] err_emails = [] for to_email in to_email_list: @@ -434,16 +412,36 @@ def repo_add_share(request): 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) + # if to_email is user name, the format is: 'example@mail.com'; + # if to_email is group, the format is 'group_name ' + if (to_email.split(' ')[0].find('@') == -1): + group_name = to_email.split(' ')[0] + group_creator = to_email.split(' ')[1] + if validate_owner(request, repo_id): + groups = ccnet_rpc.get_groups(request.user.username) + find = False + for group in groups: + if group.props.group_name == group_name and \ + group_creator.find(group.props.creator_name) >= 0: + group_share_repo(request, repo_id, int(group.props.id), from_email) + find = True + info_emails.append(group_name) + + if not find: + err_emails.append(group_name) + else: + err_emails.append(group_name) else: - err_emails.append(to_email) + 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) + output_msg['err_msg'] = u'共享给%s失败:用户或组不存在' % list_to_string(err_emails) return output_msg @@ -451,8 +449,23 @@ def repo_add_share(request): def repo_list_share(request): username = request.user.username + # repos that are share to user out_repos = seafserv_threaded_rpc.list_share_repos(username, 'from_email', -1, -1) + # repos that are share to groups + group_repos = seafserv_threaded_rpc.get_group_my_share_repos(request.user.username) + for group_repo in group_repos: + repo_id = group_repo.props.repo_id + if not repo_id: + continue + repo = get_repo(repo_id) + group_id = group_repo.props.group_id + group = ccnet_rpc.get_group(int(group_id)) + repo.props.shared_email = group.props.group_name + repo.gid = group_id + + out_repos.append(repo) + return render_to_response('share_repos.html', { "out_repos": out_repos, }, context_instance=RequestContext(request)) @@ -480,18 +493,32 @@ def repo_download(request): 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 + return go_permission_error(request, u'取消共享失败:不是目录拥有者') - 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']) + group_id = request.GET.get('gid') + + # if request params don't have 'gid', then remove repos that share to + # to other person; else, remove repos that share to groups + if not group_id: + to_email = request.GET.get('to_email', '') + seafserv_threaded_rpc.remove_share(repo_id, from_email, to_email) + else: + try: + group_id_int = int(group_id) + except: + return HttpResponseRedirect(request.META['HTTP_REFERER']) + + group_unshare_repo(request, repo_id, group_id_int, from_email) + + return HttpResponseRedirect(request.META['HTTP_REFERER']) @login_required def mypeers(request): @@ -553,8 +580,11 @@ def useradmin(request): @login_required def user_info(request, email): + if request.user.username == email: + return HttpResponseRedirect(reverse(myhome)) + if not request.user.is_staff: - raise Http404 + return go_permission_error(request, u'权限不足:无法查看该用户信息') user_dict = {} owned_repos = []