user-groups: Add update members API endpoint.

Significantly modified by tabbott to fix some bugs.
This commit is contained in:
Umair Khan
2017-11-02 12:53:30 +05:00
committed by Tim Abbott
parent a1b894a786
commit b1603d289c
6 changed files with 130 additions and 6 deletions

View File

@@ -69,7 +69,7 @@ from zerver.models import Realm, RealmEmoji, Stream, UserProfile, UserActivity,
custom_profile_fields_for_realm, get_huddle_user_ids, \
CustomProfileFieldValue, validate_attachment_request, get_system_bot, \
get_display_recipient_by_id, query_for_ids, get_huddle_recipient, \
UserGroup
UserGroup, UserGroupMembership
from zerver.lib.alert_words import alert_words_in_realm
from zerver.lib.avatar import avatar_url
@@ -4203,3 +4203,16 @@ def do_update_user_group_description(user_group, description):
# type: (UserGroup, Text) -> None
user_group.description = description
user_group.save(update_fields=['description'])
def bulk_add_members_to_user_group(user_group_id, user_profiles):
# type: (int, List[UserProfile]) -> None
memberships = [UserGroupMembership(user_group_id=user_group_id,
user_profile=user_profile)
for user_profile in user_profiles]
UserGroupMembership.objects.bulk_create(memberships)
def remove_members_from_user_group(user_group_id, user_profiles):
# type: (int, List[UserProfile]) -> None
UserGroupMembership.objects.filter(
user_group_id=user_group_id,
user_profile__in=user_profiles).delete()

View File

@@ -52,3 +52,9 @@ def create_user_group(name, members, realm, description=''):
for member in members
])
return user_group
def get_memberships_of_users(user_group, members):
# type: (UserGroup, List[UserProfile]) -> List[int]
return list(UserGroupMembership.objects.filter(
user_group=user_group,
user_profile__in=members).values_list('user_profile_id', flat=True))

View File

@@ -12,6 +12,7 @@ from zerver.lib.user_groups import (
create_user_group,
get_user_groups,
user_groups_in_realm,
get_memberships_of_users,
)
from zerver.models import UserProfile, UserGroup, get_realm, Realm, \
UserGroupMembership
@@ -148,3 +149,59 @@ class UserGroupAPITestCase(ZulipTestCase):
# Test when invalid user group is supplied
result = self.client_delete('/json/user_groups/1111')
self.assert_json_error(result, "Invalid user group")
def test_update_members_of_user_group(self):
# type: () -> None
hamlet = self.example_user('hamlet')
self.login(self.example_email("hamlet"))
params = {
'name': 'support',
'members': ujson.dumps([hamlet.id]),
'description': 'Support team',
}
self.client_post('/json/user_groups/create', info=params)
user_group = UserGroup.objects.first()
# Test add members
self.assertEqual(UserGroupMembership.objects.count(), 1)
othello = self.example_user('othello')
add = [othello.id]
params = {'add': ujson.dumps(add)}
result = self.client_post('/json/user_groups/{}/members'.format(user_group.id),
info=params)
self.assert_json_success(result)
self.assertEqual(UserGroupMembership.objects.count(), 2)
members = get_memberships_of_users(user_group, [hamlet, othello])
self.assertEqual(len(members), 2)
# Test adding a member already there.
result = self.client_post('/json/user_groups/{}/members'.format(user_group.id),
info=params)
self.assert_json_error(result, "User 6 is already a member of this group")
self.assertEqual(UserGroupMembership.objects.count(), 2)
members = get_memberships_of_users(user_group, [hamlet, othello])
self.assertEqual(len(members), 2)
# Test remove members
params = {'delete': ujson.dumps([hamlet.id, othello.id])}
result = self.client_post('/json/user_groups/{}/members'.format(user_group.id),
info=params)
self.assert_json_success(result)
self.assertEqual(UserGroupMembership.objects.count(), 0)
members = get_memberships_of_users(user_group, [hamlet, othello])
self.assertEqual(len(members), 0)
# Test remove a member that's already removed; arguably we should make this an error.
params = {'delete': ujson.dumps([hamlet.id, othello.id])}
result = self.client_post('/json/user_groups/{}/members'.format(user_group.id),
info=params)
self.assert_json_success(result)
self.assertEqual(UserGroupMembership.objects.count(), 0)
members = get_memberships_of_users(user_group, [hamlet, othello])
self.assertEqual(len(members), 0)
# Test when nothing is provided
result = self.client_post('/json/user_groups/{}/members'.format(user_group.id),
info={})
msg = 'Nothing to do. Specify at least one of "add" or "delete".'
self.assert_json_error(result, msg)

View File

@@ -1,4 +1,5 @@
from typing import Any, Optional, Tuple, List, Set, Iterable, Mapping, Callable, Dict, Text
from typing import Any, Optional, Tuple, List, Set, Iterable, Mapping, Callable, Dict, Text, \
Union
from django.utils.translation import ugettext as _
from django.conf import settings
@@ -107,7 +108,7 @@ def list_subscriptions_backend(request, user_profile):
# type: (HttpRequest, UserProfile) -> HttpResponse
return json_success({"subscriptions": gather_subscriptions(user_profile)[0]})
FuncKwargPair = Tuple[Callable[..., HttpResponse], Dict[str, Iterable[Any]]]
FuncKwargPair = Tuple[Callable[..., HttpResponse], Dict[str, Union[int, Iterable[Any]]]]
@has_request_variables
def update_subscriptions_backend(request, user_profile,

View File

@@ -5,15 +5,17 @@ from typing import List, Text
from zerver.context_processors import get_realm_from_request
from zerver.lib.actions import check_add_user_group, do_update_user_group_name, \
do_update_user_group_description
do_update_user_group_description, bulk_add_members_to_user_group, \
remove_members_from_user_group
from zerver.lib.exceptions import JsonableError
from zerver.lib.request import has_request_variables, REQ
from zerver.lib.response import json_success, json_error
from zerver.lib.users import user_ids_to_users
from zerver.lib.validator import check_list, check_string, check_int, \
check_short_string
from zerver.lib.user_groups import access_user_group_by_id
from zerver.models import UserProfile, UserGroup
from zerver.lib.user_groups import access_user_group_by_id, get_memberships_of_users
from zerver.models import UserProfile, UserGroup, UserGroupMembership
from zerver.views.streams import compose_views, FuncKwargPair
@has_request_variables
def add_user_group(request, user_profile,
@@ -52,3 +54,46 @@ def delete_user_group(request, user_profile, user_group_id=REQ(validator=check_i
user_group = access_user_group_by_id(user_group_id, user_profile.realm)
user_group.delete()
return json_success()
@has_request_variables
def update_user_group_backend(request, user_profile,
user_group_id=REQ(validator=check_int),
delete=REQ(validator=check_list(check_int), default=[]),
add=REQ(validator=check_list(check_int), default=[])):
# type: (HttpRequest, UserProfile, int, List[int], List[int]) -> HttpResponse
if not add and not delete:
return json_error(_('Nothing to do. Specify at least one of "add" or "delete".'))
method_kwarg_pairs = [
(add_members_to_group_backend,
dict(user_group_id=user_group_id, members=add)),
(remove_members_from_group_backend,
dict(user_group_id=user_group_id, members=delete))
] # type: List[FuncKwargPair]
return compose_views(request, user_profile, method_kwarg_pairs)
def add_members_to_group_backend(request, user_profile, user_group_id, members):
# type: (HttpRequest, UserProfile, int, List[int]) -> HttpResponse
if not members:
return json_success()
user_group = access_user_group_by_id(user_group_id, user_profile.realm)
user_profiles = user_ids_to_users(members, user_profile.realm)
existing_member_ids = set(get_memberships_of_users(user_group, user_profiles))
for user_profile in user_profiles:
if user_profile.id in existing_member_ids:
raise JsonableError(_("User %s is already a member of this group" % (user_profile.id,)))
bulk_add_members_to_user_group(user_group_id, user_profiles)
return json_success()
def remove_members_from_group_backend(request, user_profile, user_group_id, members):
# type: (HttpRequest, UserProfile, int, List[int]) -> HttpResponse
if not members:
return json_success()
user_profiles = user_ids_to_users(members, user_profile.realm)
user_group = access_user_group_by_id(user_group_id, user_profile.realm)
remove_members_from_user_group(user_group, user_profiles)
return json_success()

View File

@@ -221,6 +221,8 @@ v1_api_and_json_patterns = [
url(r'^user_groups/(?P<user_group_id>\d+)$', rest_dispatch,
{'PATCH': 'zerver.views.user_groups.edit_user_group',
'DELETE': 'zerver.views.user_groups.delete_user_group'}),
url(r'^user_groups/(?P<user_group_id>\d+)/members$', rest_dispatch,
{'POST': 'zerver.views.user_groups.update_user_group_backend'}),
# users/me -> zerver.views.user_settings
url(r'^users/me/api_key/regenerate$', rest_dispatch,