diff --git a/seahub/api2/endpoints/group_members.py b/seahub/api2/endpoints/group_members.py index ca2bc5618d..9d00686281 100644 --- a/seahub/api2/endpoints/group_members.py +++ b/seahub/api2/endpoints/group_members.py @@ -9,6 +9,7 @@ from rest_framework.views import APIView from rest_framework import status import seaserv +from seaserv import seafile_api from pysearpc import SearpcError from seahub.profile.models import Profile @@ -18,7 +19,7 @@ from seahub.api2.authentication import TokenAuthentication from seahub.avatar.settings import AVATAR_DEFAULT_SIZE from seahub.avatar.templatetags.avatar_tags import api_avatar_url, \ get_default_avatar_url -from seahub.utils import is_valid_username +from seahub.utils import is_valid_username, string2list, is_org_context from seahub.base.templatetags.seahub_tags import email2nickname from seahub.base.accounts import User @@ -29,7 +30,7 @@ logger = logging.getLogger(__name__) def get_group_member_info(request, group_id, email, avatar_size=AVATAR_DEFAULT_SIZE): p = Profile.objects.get_profile_by_user(email) if p: - login_id = p.login_id if p.login_id != '' else '' + login_id = p.login_id if p.login_id else '' else: login_id = '' @@ -73,22 +74,18 @@ class GroupMembers(APIView): members = seaserv.get_group_members(group_id) except SearpcError as e: logger.error(e) - error_msg = _(u'Internal Server Error') + error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) - try: - only_admin = int(request.GET.get('only_admin', 0)) - except ValueError: - only_admin = 0 - - if only_admin not in (0, 1): - error_msg = _(u'Argument is not valid') + is_admin = request.GET.get('is_admin', 'false') + if is_admin.lower() not in ('true', 'false'): + error_msg = 'is_admin invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) group_members = [] for m in members: # only return group admins - if only_admin and not m.is_staff: + if is_admin == 'true' and not m.is_staff: continue member_info = get_group_member_info(request, group_id, m.user_name, avatar_size) @@ -102,22 +99,179 @@ class GroupMembers(APIView): Add a group member. """ username = request.user.username - email = request.data.get('email', None) try: User.objects.get(email=email) except User.DoesNotExist: - error_msg = _(u'Invalid username') + error_msg = 'Email %s invalid.' % email return api_error(status.HTTP_400_BAD_REQUEST, error_msg) try: - seaserv.group_add_member(group_id, username, email) + seaserv.ccnet_threaded_rpc.group_add_member(group_id, username, email) except SearpcError as e: logger.error(e) - error_msg = _(u'Internal Server Error') + error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) - member_info = get_group_member_info(request, group_id, email, AVATAR_DEFAULT_SIZE) + member_info = get_group_member_info(request, group_id, email) return Response(member_info, status=status.HTTP_201_CREATED) + + +class GroupMember(APIView): + authentication_classes = (TokenAuthentication, SessionAuthentication) + permission_classes = (IsAuthenticated,) + throttle_classes = (UserRateThrottle, ) + + @api_check_group_member + def get(self, request, group_id, email): + """ + Get info of a specific group member. + """ + try: + avatar_size = int(request.GET.get('avatar_size', + AVATAR_DEFAULT_SIZE)) + except ValueError: + avatar_size = AVATAR_DEFAULT_SIZE + + member_info = get_group_member_info(request, group_id, email, avatar_size) + + return Response(member_info) + + @api_check_group_staff + def put(self, request, group_id, email): + """ + Set/unset a specific group member as admin. + """ + + is_admin = request.data.get('is_admin', '') + if is_admin.lower() == 'true': + try: + seaserv.ccnet_threaded_rpc.group_set_admin(group_id, email) + except SearpcError as e: + logger.error(e) + error_msg = 'Internal Server Error' + return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) + + elif is_admin.lower() == 'false': + try: + seaserv.ccnet_threaded_rpc.group_unset_admin(group_id, email) + except SearpcError as e: + logger.error(e) + error_msg = 'Internal Server Error' + return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) + + else: + error_msg = 'is_admin invalid.' + return api_error(status.HTTP_400_BAD_REQUEST, error_msg) + + member_info = get_group_member_info(request, group_id, email) + + return Response(member_info) + + @api_check_group_member + def delete(self, request, group_id, email): + """ + Delete a group member. + """ + username = request.user.username + + if not is_valid_username(email): + error_msg = 'Email %s invalid.' % email + return api_error(status.HTTP_400_BAD_REQUEST, error_msg) + + if username == email: + # user leave group + try: + seaserv.ccnet_threaded_rpc.quit_group(group_id, username) + seafile_api.remove_group_repos_by_owner(group_id, email) + except SearpcError as e: + logger.error(e) + error_msg = 'Internal Server Error' + return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) + else: + # admin delete group memeber + try: + if not seaserv.check_group_staff(group_id, username): + error_msg = 'Permission denied.' + return api_error(status.HTTP_403_FORBIDDEN, error_msg) + + seaserv.ccnet_threaded_rpc.group_remove_member(group_id, username, email) + seafile_api.remove_group_repos_by_owner(group_id, email) + except SearpcError as e: + logger.error(e) + error_msg = 'Internal Server Error' + return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) + + return Response({'success': True}) + + +class GroupMembersBulk(APIView): + authentication_classes = (TokenAuthentication, SessionAuthentication) + permission_classes = (IsAuthenticated,) + throttle_classes = (UserRateThrottle, ) + + @api_check_group_staff + def post(self, request, group_id): + """ + Bulk add group members. + """ + username = request.user.username + + emails_str = request.data.get('emails', '') + emails_list = string2list(emails_str) + emails_list = [x.lower() for x in emails_list] + + result = {} + result['failed'] = [] + result['success'] = [] + emails_need_add = [] + + org_id = None + if is_org_context(request): + org_id = request.user.org.org_id + + for email in emails_list: + try: + User.objects.get(email=email) + except User.DoesNotExist: + result['failed'].append({ + 'email': email, + 'error_msg': 'Email %s invalid.' % email + }) + continue + + if seaserv.is_group_user(group_id, email): + result['failed'].append({ + 'email': email, + 'error_msg': _(u'User %s is already a group member.') % email + }) + continue + + # Can only invite organization users to group + if org_id and not \ + seaserv.ccnet_threaded_rpc.org_user_exists(org_id, email): + result['failed'].append({ + 'email': email, + 'error_msg': _(u'User %s not found in organizaiont.') % email + }) + continue + + emails_need_add.append(email) + + # Add user to group. + for email in emails_need_add: + try: + seaserv.ccnet_threaded_rpc.group_add_member(group_id, + username, email) + member_info = get_group_member_info(request, group_id, email) + result['success'].append(member_info) + except SearpcError as e: + logger.error(e) + result['failed'].append({ + 'email': email, + 'error_msg': 'Internal Server Error' + }) + + return Response(result) diff --git a/seahub/api2/endpoints/groups.py b/seahub/api2/endpoints/groups.py index f40a7699d9..69c22d17a6 100644 --- a/seahub/api2/endpoints/groups.py +++ b/seahub/api2/endpoints/groups.py @@ -27,7 +27,8 @@ from seahub.group.views import remove_group_common from seahub.base.templatetags.seahub_tags import email2nickname, \ translate_seahub_time -from .utils import api_check_group_staff +from .utils import api_check_group_staff, api_check_group_member, \ + api_check_group_owner logger = logging.getLogger(__name__) @@ -53,7 +54,7 @@ def get_group_info(request, group_id, avatar_size=GROUP_AVATAR_DEFAULT_SIZE): group_info = { "id": group.id, "name": group.group_name, - "creator": group.creator_name, + "owner": group.creator_name, "created_at": val.strftime("%Y-%m-%dT%H:%M:%S") + DateFormat(val).format('O'), "avatar_url": request.build_absolute_uri(avatar_url), "admins": get_group_admins(group.id), @@ -84,9 +85,9 @@ class Groups(APIView): user_groups = seaserv.get_personal_groups_by_user(username) try: - size = int(request.GET.get('avatar_size', GROUP_AVATAR_DEFAULT_SIZE)) + avatar_size = int(request.GET.get('avatar_size', GROUP_AVATAR_DEFAULT_SIZE)) except ValueError: - size = GROUP_AVATAR_DEFAULT_SIZE + avatar_size = GROUP_AVATAR_DEFAULT_SIZE try: with_repos = int(request.GET.get('with_repos', 0)) @@ -94,12 +95,12 @@ class Groups(APIView): with_repos = 0 if with_repos not in (0, 1): - error_msg = _(u'Argument can only be 0 or 1') + error_msg = 'with_repos invalid.' return api_error(status.HTTP_400_BAD_REQUEST, error_msg) groups = [] for g in user_groups: - group_info = get_group_info(request, g.id , size) + group_info = get_group_info(request, g.id , avatar_size) if with_repos: if org_id: @@ -112,7 +113,6 @@ class Groups(APIView): repo = { "id": r.id, "name": r.name, - "desc": r.desc, "size": r.size, "size_formatted": filesizeformat(r.size), "mtime": r.last_modified, @@ -120,8 +120,7 @@ class Groups(APIView): "encrypted": r.encrypted, "permission": r.permission, "owner": r.user, - "owner_nickname": email2nickname(r.user), - "share_from_me": True if username == r.user else False, + "owner_name": email2nickname(r.user), } repos.append(repo) @@ -135,7 +134,7 @@ class Groups(APIView): """ Create a group """ if not self._can_add_group(request): - error_msg = _(u'You do not have permission to create group.') + error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) username = request.user.username @@ -157,11 +156,11 @@ class Groups(APIView): group_id = seaserv.ccnet_threaded_rpc.create_group(group_name, username) except SearpcError as e: logger.error(e) - error_msg = _(u'Failed') + error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) # get info of new group - group_info = get_group_info(request, group_id, GROUP_AVATAR_DEFAULT_SIZE) + group_info = get_group_info(request, group_id) return Response(group_info, status=status.HTTP_201_CREATED) @@ -172,6 +171,19 @@ class Group(APIView): permission_classes = (IsAuthenticated,) throttle_classes = (UserRateThrottle, ) + @api_check_group_member + def get(self, request, group_id): + """ Get info of a group. + """ + + try: + avatar_size = int(request.GET.get('avatar_size', GROUP_AVATAR_DEFAULT_SIZE)) + except ValueError: + avatar_size = GROUP_AVATAR_DEFAULT_SIZE + + group_info = get_group_info(request, group_id, avatar_size) + return Response(group_info) + @api_check_group_staff def put(self, request, group_id): """ Rename, transfer a specific group @@ -197,39 +209,45 @@ class Group(APIView): seaserv.ccnet_threaded_rpc.set_group_name(group_id, new_group_name) except SearpcError as e: logger.error(e) - error_msg = _(u'Internal Server Error') + error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) - new_creator= request.data.get('creator', None) - if new_creator: + new_owner = request.data.get('owner', None) + if new_owner: # transfer a group - if not is_valid_username(new_creator): - error_msg = _('Creator %s is not valid.') % new_creator + + # only group owner can transfer a group + if not (username == group.creator_name): + error_msg = 'Permission denied.' + return api_error(status.HTTP_403_FORBIDDEN, error_msg) + + if not is_valid_username(new_owner): + error_msg = 'Email %s invalid.' % new_owner return api_error(status.HTTP_400_BAD_REQUEST, error_msg) - if new_creator == group.creator_name: - error_msg = _('%s is already group owner') % new_creator + if new_owner == group.creator_name: + error_msg = _(u'User %s is already group owner.') % new_owner return api_error(status.HTTP_400_BAD_REQUEST, error_msg) try: - if not seaserv.is_group_user(group_id, new_creator): - seaserv.ccnet_threaded_rpc.group_add_member(group_id, username, new_creator) + if not seaserv.is_group_user(group_id, new_owner): + seaserv.ccnet_threaded_rpc.group_add_member(group_id, username, new_owner) - if not seaserv.check_group_staff(group_id, new_creator): - seaserv.ccnet_threaded_rpc.group_set_admin(group_id, new_creator) + if not seaserv.check_group_staff(group_id, new_owner): + seaserv.ccnet_threaded_rpc.group_set_admin(group_id, new_owner) - seaserv.ccnet_threaded_rpc.set_group_creator(group_id, new_creator) + seaserv.ccnet_threaded_rpc.set_group_creator(group_id, new_owner) except SearpcError as e: logger.error(e) - error_msg = _(u'Internal Server Error') + error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) # get new info of this group - group_info = get_group_info(request, group_id, GROUP_AVATAR_DEFAULT_SIZE) + group_info = get_group_info(request, group_id) return Response(group_info) - @api_check_group_staff + @api_check_group_owner def delete(self, request, group_id): """ Delete a specific group """ @@ -244,7 +262,7 @@ class Group(APIView): remove_group_common(group_id, username, org_id=org_id) except SearpcError as e: logger.error(e) - error_msg = _(u'Internal Server Error') + error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) return Response({'success': True}) diff --git a/seahub/api2/endpoints/utils.py b/seahub/api2/endpoints/utils.py index e8c6f6ed1a..13a0c9c801 100644 --- a/seahub/api2/endpoints/utils.py +++ b/seahub/api2/endpoints/utils.py @@ -1,7 +1,5 @@ import logging -from django.utils.translation import ugettext as _ - from rest_framework import status import seaserv @@ -21,11 +19,11 @@ def api_check_group_member(func): group = seaserv.get_group(group_id) except SearpcError as e: logger.error(e) - error_msg = _(u'Internal Server Error') + error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) if not group: - error_msg = _(u'Group does not exist.') + error_msg = 'Group %d not found.' % group_id return api_error(status.HTTP_400_BAD_REQUEST, error_msg) username = request.user.username @@ -34,18 +32,17 @@ def api_check_group_member(func): username) except SearpcError as e: logger.error(e) - error_msg = _(u'Internal Server Error') + error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) if not is_group_member: - error_msg = _(u'Permission denied') + error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) return func(view, request, group_id, *args, **kwargs) return _decorated - def api_check_group_staff(func): """ Decorator for check if group valid and if is group staff @@ -56,35 +53,49 @@ def api_check_group_staff(func): group = seaserv.get_group(group_id) except SearpcError as e: logger.error(e) - error_msg = _(u'Internal Server Error') + error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) if not group: - error_msg = _(u'Group does not exist.') + error_msg = 'Group %d not found.' % group_id return api_error(status.HTTP_400_BAD_REQUEST, error_msg) username = request.user.username - try: - is_group_member = seaserv.is_group_user(group_id, - username) - except SearpcError as e: - logger.error(e) - error_msg = _(u'Internal Server Error') - return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) - - if not is_group_member: - error_msg = _(u'Permission denied') - return api_error(status.HTTP_403_FORBIDDEN, error_msg) - try: is_group_staff = seaserv.check_group_staff(group_id, username) except SearpcError as e: logger.error(e) - error_msg = _(u'Internal Server Error') + error_msg = 'Internal Server Error' return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) if not is_group_staff: - error_msg = _(u'Permission denied') + error_msg = 'Permission denied.' + return api_error(status.HTTP_403_FORBIDDEN, error_msg) + + return func(view, request, group_id, *args, **kwargs) + + return _decorated + +def api_check_group_owner(func): + """ + Decorator for check if group valid and if is group owner + """ + def _decorated(view, request, group_id, *args, **kwargs): + group_id = int(group_id) # Checked by URL Conf + try: + group = seaserv.get_group(group_id) + except SearpcError as e: + logger.error(e) + error_msg = 'Internal Server Error' + return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg) + + if not group: + error_msg = 'Group %d not found.' % group_id + return api_error(status.HTTP_400_BAD_REQUEST, error_msg) + + username = request.user.username + if not (username == group.creator_name): + error_msg = 'Permission denied.' return api_error(status.HTTP_403_FORBIDDEN, error_msg) return func(view, request, group_id, *args, **kwargs) diff --git a/seahub/urls.py b/seahub/urls.py index f91c8ce262..82fcc59a8d 100644 --- a/seahub/urls.py +++ b/seahub/urls.py @@ -20,7 +20,7 @@ from seahub.views.wiki import personal_wiki, personal_wiki_pages, \ from seahub.views.sysadmin import * from seahub.views.ajax import * from seahub.api2.endpoints.groups import Groups, Group -from seahub.api2.endpoints.group_members import GroupMembers +from seahub.api2.endpoints.group_members import GroupMembers, GroupMembersBulk, GroupMember # Uncomment the next two lines to enable the admin: #from django.contrib import admin @@ -196,6 +196,8 @@ urlpatterns = patterns( url(r'^api/v2.1/groups/$', Groups.as_view(), name='api-v2.1-groups'), url(r'^api/v2.1/groups/(?P\d+)/$', Group.as_view(), name='api-v2.1-group'), url(r'^api/v2.1/groups/(?P\d+)/members/$', GroupMembers.as_view(), name='api-v2.1-group-members'), + url(r'^api/v2.1/groups/(?P\d+)/members/bulk/$', GroupMembersBulk.as_view(), name='api-v2.1-group-members-bulk'), + url(r'^api/v2.1/groups/(?P\d+)/members/(?P[^/]+)/$', GroupMember.as_view(), name='api-v2.1-group-member'), (r'^avatar/', include('seahub.avatar.urls')), (r'^notification/', include('seahub.notifications.urls')), (r'^contacts/', include('seahub.contacts.urls')),