mirror of
https://github.com/zulip/zulip.git
synced 2025-11-21 15:09:34 +00:00
models: Use COMMON_POLICY_TYPES for user_group_edit_policy.
This commit adds moderators and full members options for user_group_edit_policy by using COMMON_POLICY_TYPES. Moderators do not require to be a member of user group in order to edit or remove the user group if they are allowed to do so according to user_group_edit_policy. But full members need to be a member of user group to edit or remove the user group.
This commit is contained in:
@@ -575,12 +575,8 @@ def require_user_group_edit_permission(view_func: ViewFuncT) -> ViewFuncT:
|
|||||||
def _wrapped_view_func(
|
def _wrapped_view_func(
|
||||||
request: HttpRequest, user_profile: UserProfile, *args: object, **kwargs: object
|
request: HttpRequest, user_profile: UserProfile, *args: object, **kwargs: object
|
||||||
) -> HttpResponse:
|
) -> HttpResponse:
|
||||||
realm = user_profile.realm
|
if not user_profile.can_edit_user_groups():
|
||||||
if (
|
raise JsonableError(_("Insufficient permission"))
|
||||||
realm.user_group_edit_policy != Realm.USER_GROUP_EDIT_POLICY_MEMBERS
|
|
||||||
and not user_profile.is_realm_admin
|
|
||||||
):
|
|
||||||
raise OrganizationAdministratorRequired()
|
|
||||||
return view_func(request, user_profile, *args, **kwargs)
|
return view_func(request, user_profile, *args, **kwargs)
|
||||||
|
|
||||||
return cast(ViewFuncT, _wrapped_view_func) # https://github.com/python/mypy/issues/1927
|
return cast(ViewFuncT, _wrapped_view_func) # https://github.com/python/mypy/issues/1927
|
||||||
|
|||||||
@@ -11,7 +11,11 @@ def access_user_group_by_id(user_group_id: int, user_profile: UserProfile) -> Us
|
|||||||
try:
|
try:
|
||||||
user_group = UserGroup.objects.get(id=user_group_id, realm=user_profile.realm)
|
user_group = UserGroup.objects.get(id=user_group_id, realm=user_profile.realm)
|
||||||
group_member_ids = get_user_group_members(user_group)
|
group_member_ids = get_user_group_members(user_group)
|
||||||
if not user_profile.is_realm_admin and user_profile.id not in group_member_ids:
|
if (
|
||||||
|
not user_profile.is_realm_admin
|
||||||
|
and not user_profile.is_moderator
|
||||||
|
and user_profile.id not in group_member_ids
|
||||||
|
):
|
||||||
raise JsonableError(_("Insufficient permission"))
|
raise JsonableError(_("Insufficient permission"))
|
||||||
except UserGroup.DoesNotExist:
|
except UserGroup.DoesNotExist:
|
||||||
raise JsonableError(_("Invalid user group"))
|
raise JsonableError(_("Invalid user group"))
|
||||||
|
|||||||
@@ -291,15 +291,7 @@ class Realm(models.Model):
|
|||||||
default=POLICY_ADMINS_ONLY
|
default=POLICY_ADMINS_ONLY
|
||||||
)
|
)
|
||||||
|
|
||||||
USER_GROUP_EDIT_POLICY_MEMBERS = 1
|
user_group_edit_policy: int = models.PositiveSmallIntegerField(default=POLICY_MEMBERS_ONLY)
|
||||||
USER_GROUP_EDIT_POLICY_ADMINS = 2
|
|
||||||
user_group_edit_policy: int = models.PositiveSmallIntegerField(
|
|
||||||
default=USER_GROUP_EDIT_POLICY_MEMBERS
|
|
||||||
)
|
|
||||||
USER_GROUP_EDIT_POLICY_TYPES = [
|
|
||||||
USER_GROUP_EDIT_POLICY_MEMBERS,
|
|
||||||
USER_GROUP_EDIT_POLICY_ADMINS,
|
|
||||||
]
|
|
||||||
|
|
||||||
PRIVATE_MESSAGE_POLICY_UNLIMITED = 1
|
PRIVATE_MESSAGE_POLICY_UNLIMITED = 1
|
||||||
PRIVATE_MESSAGE_POLICY_DISABLED = 2
|
PRIVATE_MESSAGE_POLICY_DISABLED = 2
|
||||||
|
|||||||
@@ -3464,6 +3464,8 @@ paths:
|
|||||||
|
|
||||||
* 1 = All members can create and edit user groups
|
* 1 = All members can create and edit user groups
|
||||||
* 2 = Only organization administrators can create and edit user groups
|
* 2 = Only organization administrators can create and edit user groups
|
||||||
|
* 3 = Only full members can create and edit user groups
|
||||||
|
* 4 = Only organization administrators and moderators can create and edit user groups
|
||||||
default_code_block_language:
|
default_code_block_language:
|
||||||
type: string
|
type: string
|
||||||
nullable: true
|
nullable: true
|
||||||
@@ -9009,6 +9011,8 @@ paths:
|
|||||||
|
|
||||||
* 1 = All members can create and edit user groups
|
* 1 = All members can create and edit user groups
|
||||||
* 2 = Only organization administrators can create and edit user groups
|
* 2 = Only organization administrators can create and edit user groups
|
||||||
|
* 3 = Only full members can create and edit user groups.
|
||||||
|
* 4 = Only organization administrators and moderators can create and edit user groups.
|
||||||
realm_default_code_block_language:
|
realm_default_code_block_language:
|
||||||
type: string
|
type: string
|
||||||
nullable: true
|
nullable: true
|
||||||
|
|||||||
@@ -2029,7 +2029,7 @@ class RealmPropertyActionTest(BaseAction):
|
|||||||
create_stream_policy=[4, 3, 2, 1],
|
create_stream_policy=[4, 3, 2, 1],
|
||||||
invite_to_stream_policy=[4, 3, 2, 1],
|
invite_to_stream_policy=[4, 3, 2, 1],
|
||||||
private_message_policy=[2, 1],
|
private_message_policy=[2, 1],
|
||||||
user_group_edit_policy=[1, 2],
|
user_group_edit_policy=[1, 2, 3, 4],
|
||||||
wildcard_mention_policy=[7, 6, 5, 4, 3, 2, 1],
|
wildcard_mention_policy=[7, 6, 5, 4, 3, 2, 1],
|
||||||
email_address_visibility=[Realm.EMAIL_ADDRESS_VISIBILITY_ADMINS],
|
email_address_visibility=[Realm.EMAIL_ADDRESS_VISIBILITY_ADMINS],
|
||||||
bot_creation_policy=[Realm.BOT_CREATION_EVERYONE],
|
bot_creation_policy=[Realm.BOT_CREATION_EVERYONE],
|
||||||
|
|||||||
@@ -757,7 +757,7 @@ class RealmAPITest(ZulipTestCase):
|
|||||||
name=["Zulip", "New Name"],
|
name=["Zulip", "New Name"],
|
||||||
waiting_period_threshold=[10, 20],
|
waiting_period_threshold=[10, 20],
|
||||||
create_stream_policy=Realm.COMMON_POLICY_TYPES,
|
create_stream_policy=Realm.COMMON_POLICY_TYPES,
|
||||||
user_group_edit_policy=Realm.USER_GROUP_EDIT_POLICY_TYPES,
|
user_group_edit_policy=Realm.COMMON_POLICY_TYPES,
|
||||||
private_message_policy=Realm.PRIVATE_MESSAGE_POLICY_TYPES,
|
private_message_policy=Realm.PRIVATE_MESSAGE_POLICY_TYPES,
|
||||||
invite_to_stream_policy=Realm.COMMON_POLICY_TYPES,
|
invite_to_stream_policy=Realm.COMMON_POLICY_TYPES,
|
||||||
wildcard_mention_policy=Realm.WILDCARD_MENTION_POLICY_TYPES,
|
wildcard_mention_policy=Realm.WILDCARD_MENTION_POLICY_TYPES,
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
|
from datetime import timedelta
|
||||||
|
from typing import Optional
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
import orjson
|
import orjson
|
||||||
|
from django.utils.timezone import now as timezone_now
|
||||||
|
|
||||||
from zerver.lib.actions import do_set_realm_property, ensure_stream
|
from zerver.lib.actions import do_set_realm_property, ensure_stream
|
||||||
from zerver.lib.test_classes import ZulipTestCase
|
from zerver.lib.test_classes import ZulipTestCase
|
||||||
@@ -77,7 +80,7 @@ class UserGroupTestCase(ZulipTestCase):
|
|||||||
self.assertFalse(check_remove_user_from_user_group(othello, user_group))
|
self.assertFalse(check_remove_user_from_user_group(othello, user_group))
|
||||||
|
|
||||||
|
|
||||||
class UserGroupAPITestCase(ZulipTestCase):
|
class UserGroupAPITestCase(UserGroupTestCase):
|
||||||
def test_user_group_create(self) -> None:
|
def test_user_group_create(self) -> None:
|
||||||
hamlet = self.example_user("hamlet")
|
hamlet = self.example_user("hamlet")
|
||||||
|
|
||||||
@@ -129,19 +132,6 @@ class UserGroupAPITestCase(ZulipTestCase):
|
|||||||
|
|
||||||
self.check_has_permission_policies("user_group_edit_policy", validation_func)
|
self.check_has_permission_policies("user_group_edit_policy", validation_func)
|
||||||
|
|
||||||
def test_user_group_create_by_guest_user(self) -> None:
|
|
||||||
guest_user = self.example_user("polonius")
|
|
||||||
|
|
||||||
# Guest users can't create user group
|
|
||||||
self.login_user(guest_user)
|
|
||||||
params = {
|
|
||||||
"name": "support",
|
|
||||||
"members": orjson.dumps([guest_user.id]).decode(),
|
|
||||||
"description": "Support team",
|
|
||||||
}
|
|
||||||
result = self.client_post("/json/user_groups/create", info=params)
|
|
||||||
self.assert_json_error(result, "Not allowed for guest users")
|
|
||||||
|
|
||||||
def test_user_group_update(self) -> None:
|
def test_user_group_update(self) -> None:
|
||||||
hamlet = self.example_user("hamlet")
|
hamlet = self.example_user("hamlet")
|
||||||
self.login("hamlet")
|
self.login("hamlet")
|
||||||
@@ -169,50 +159,6 @@ class UserGroupAPITestCase(ZulipTestCase):
|
|||||||
result = self.client_patch("/json/user_groups/1111", info=params)
|
result = self.client_patch("/json/user_groups/1111", info=params)
|
||||||
self.assert_json_error(result, "Invalid user group")
|
self.assert_json_error(result, "Invalid user group")
|
||||||
|
|
||||||
self.logout()
|
|
||||||
# Test when user not a member of user group tries to modify it
|
|
||||||
cordelia = self.example_user("cordelia")
|
|
||||||
self.login_user(cordelia)
|
|
||||||
params = {
|
|
||||||
"name": "help",
|
|
||||||
"description": "Troubleshooting",
|
|
||||||
}
|
|
||||||
result = self.client_patch(f"/json/user_groups/{user_group.id}", info=params)
|
|
||||||
self.assert_json_error(result, "Insufficient permission")
|
|
||||||
|
|
||||||
self.logout()
|
|
||||||
# Test when organization admin tries to modify group
|
|
||||||
iago = self.example_user("iago")
|
|
||||||
self.login_user(iago)
|
|
||||||
params = {
|
|
||||||
"name": "help",
|
|
||||||
"description": "Troubleshooting",
|
|
||||||
}
|
|
||||||
result = self.client_patch(f"/json/user_groups/{user_group.id}", info=params)
|
|
||||||
self.assert_json_success(result)
|
|
||||||
|
|
||||||
def test_user_group_update_by_guest_user(self) -> None:
|
|
||||||
hamlet = self.example_user("hamlet")
|
|
||||||
guest_user = self.example_user("polonius")
|
|
||||||
self.login_user(hamlet)
|
|
||||||
params = {
|
|
||||||
"name": "support",
|
|
||||||
"members": orjson.dumps([hamlet.id, guest_user.id]).decode(),
|
|
||||||
"description": "Support team",
|
|
||||||
}
|
|
||||||
result = self.client_post("/json/user_groups/create", info=params)
|
|
||||||
self.assert_json_success(result)
|
|
||||||
user_group = UserGroup.objects.get(name="support")
|
|
||||||
|
|
||||||
# Guest user can't edit any detail of an user group
|
|
||||||
self.login_user(guest_user)
|
|
||||||
params = {
|
|
||||||
"name": "help",
|
|
||||||
"description": "Troubleshooting team",
|
|
||||||
}
|
|
||||||
result = self.client_patch(f"/json/user_groups/{user_group.id}", info=params)
|
|
||||||
self.assert_json_error(result, "Not allowed for guest users")
|
|
||||||
|
|
||||||
def test_user_group_update_to_already_existing_name(self) -> None:
|
def test_user_group_update_to_already_existing_name(self) -> None:
|
||||||
hamlet = self.example_user("hamlet")
|
hamlet = self.example_user("hamlet")
|
||||||
self.login_user(hamlet)
|
self.login_user(hamlet)
|
||||||
@@ -248,51 +194,6 @@ class UserGroupAPITestCase(ZulipTestCase):
|
|||||||
result = self.client_delete("/json/user_groups/1111")
|
result = self.client_delete("/json/user_groups/1111")
|
||||||
self.assert_json_error(result, "Invalid user group")
|
self.assert_json_error(result, "Invalid user group")
|
||||||
|
|
||||||
# Test when user not a member of user group tries to delete it
|
|
||||||
params = {
|
|
||||||
"name": "Development",
|
|
||||||
"members": orjson.dumps([hamlet.id]).decode(),
|
|
||||||
"description": "Development team",
|
|
||||||
}
|
|
||||||
self.client_post("/json/user_groups/create", info=params)
|
|
||||||
user_group = UserGroup.objects.get(name="Development")
|
|
||||||
self.assertEqual(UserGroup.objects.count(), 2)
|
|
||||||
self.logout()
|
|
||||||
cordelia = self.example_user("cordelia")
|
|
||||||
self.login_user(cordelia)
|
|
||||||
|
|
||||||
result = self.client_delete(f"/json/user_groups/{user_group.id}")
|
|
||||||
self.assert_json_error(result, "Insufficient permission")
|
|
||||||
self.assertEqual(UserGroup.objects.count(), 2)
|
|
||||||
|
|
||||||
self.logout()
|
|
||||||
# Test when organization admin tries to delete group
|
|
||||||
iago = self.example_user("iago")
|
|
||||||
self.login_user(iago)
|
|
||||||
|
|
||||||
result = self.client_delete(f"/json/user_groups/{user_group.id}")
|
|
||||||
self.assert_json_success(result)
|
|
||||||
self.assertEqual(UserGroup.objects.count(), 1)
|
|
||||||
self.assertEqual(UserGroupMembership.objects.count(), 2)
|
|
||||||
|
|
||||||
def test_user_group_delete_by_guest_user(self) -> None:
|
|
||||||
hamlet = self.example_user("hamlet")
|
|
||||||
guest_user = self.example_user("polonius")
|
|
||||||
self.login_user(hamlet)
|
|
||||||
params = {
|
|
||||||
"name": "support",
|
|
||||||
"members": orjson.dumps([hamlet.id, guest_user.id]).decode(),
|
|
||||||
"description": "Support team",
|
|
||||||
}
|
|
||||||
result = self.client_post("/json/user_groups/create", info=params)
|
|
||||||
self.assert_json_success(result)
|
|
||||||
user_group = UserGroup.objects.get(name="support")
|
|
||||||
|
|
||||||
# Guest users can't delete any user group(not even those of which they are a member)
|
|
||||||
self.login_user(guest_user)
|
|
||||||
result = self.client_delete(f"/json/user_groups/{user_group.id}")
|
|
||||||
self.assert_json_error(result, "Not allowed for guest users")
|
|
||||||
|
|
||||||
def test_update_members_of_user_group(self) -> None:
|
def test_update_members_of_user_group(self) -> None:
|
||||||
hamlet = self.example_user("hamlet")
|
hamlet = self.example_user("hamlet")
|
||||||
self.login("hamlet")
|
self.login("hamlet")
|
||||||
@@ -322,28 +223,7 @@ class UserGroupAPITestCase(ZulipTestCase):
|
|||||||
members = get_memberships_of_users(user_group, [hamlet, othello])
|
members = get_memberships_of_users(user_group, [hamlet, othello])
|
||||||
self.assert_length(members, 2)
|
self.assert_length(members, 2)
|
||||||
|
|
||||||
self.logout()
|
|
||||||
# Test when user not a member of user group tries to add members to it
|
|
||||||
cordelia = self.example_user("cordelia")
|
|
||||||
self.login_user(cordelia)
|
|
||||||
add = [cordelia.id]
|
|
||||||
params = {"add": orjson.dumps(add).decode()}
|
|
||||||
result = self.client_post(f"/json/user_groups/{user_group.id}/members", info=params)
|
|
||||||
self.assert_json_error(result, "Insufficient permission")
|
|
||||||
self.assertEqual(UserGroupMembership.objects.count(), 4)
|
|
||||||
|
|
||||||
self.logout()
|
|
||||||
# Test when organization admin tries to add members to group
|
|
||||||
iago = self.example_user("iago")
|
|
||||||
self.login_user(iago)
|
|
||||||
aaron = self.example_user("aaron")
|
aaron = self.example_user("aaron")
|
||||||
add = [aaron.id]
|
|
||||||
params = {"add": orjson.dumps(add).decode()}
|
|
||||||
result = self.client_post(f"/json/user_groups/{user_group.id}/members", info=params)
|
|
||||||
self.assert_json_success(result)
|
|
||||||
self.assertEqual(UserGroupMembership.objects.count(), 5)
|
|
||||||
members = get_memberships_of_users(user_group, [hamlet, othello, aaron])
|
|
||||||
self.assert_length(members, 3)
|
|
||||||
|
|
||||||
# For normal testing we again log in with hamlet
|
# For normal testing we again log in with hamlet
|
||||||
self.logout()
|
self.logout()
|
||||||
@@ -352,41 +232,23 @@ class UserGroupAPITestCase(ZulipTestCase):
|
|||||||
params = {"delete": orjson.dumps([othello.id]).decode()}
|
params = {"delete": orjson.dumps([othello.id]).decode()}
|
||||||
result = self.client_post(f"/json/user_groups/{user_group.id}/members", info=params)
|
result = self.client_post(f"/json/user_groups/{user_group.id}/members", info=params)
|
||||||
self.assert_json_success(result)
|
self.assert_json_success(result)
|
||||||
self.assertEqual(UserGroupMembership.objects.count(), 4)
|
self.assertEqual(UserGroupMembership.objects.count(), 3)
|
||||||
members = get_memberships_of_users(user_group, [hamlet, othello, aaron])
|
members = get_memberships_of_users(user_group, [hamlet, othello, aaron])
|
||||||
self.assert_length(members, 2)
|
self.assert_length(members, 1)
|
||||||
|
|
||||||
# Test remove a member that's already removed
|
# Test remove a member that's already removed
|
||||||
params = {"delete": orjson.dumps([othello.id]).decode()}
|
params = {"delete": orjson.dumps([othello.id]).decode()}
|
||||||
result = self.client_post(f"/json/user_groups/{user_group.id}/members", info=params)
|
result = self.client_post(f"/json/user_groups/{user_group.id}/members", info=params)
|
||||||
self.assert_json_error(result, f"There is no member '{othello.id}' in this user group")
|
self.assert_json_error(result, f"There is no member '{othello.id}' in this user group")
|
||||||
self.assertEqual(UserGroupMembership.objects.count(), 4)
|
self.assertEqual(UserGroupMembership.objects.count(), 3)
|
||||||
members = get_memberships_of_users(user_group, [hamlet, othello, aaron])
|
members = get_memberships_of_users(user_group, [hamlet, othello, aaron])
|
||||||
self.assert_length(members, 2)
|
self.assert_length(members, 1)
|
||||||
|
|
||||||
# Test when nothing is provided
|
# Test when nothing is provided
|
||||||
result = self.client_post(f"/json/user_groups/{user_group.id}/members", info={})
|
result = self.client_post(f"/json/user_groups/{user_group.id}/members", info={})
|
||||||
msg = 'Nothing to do. Specify at least one of "add" or "delete".'
|
msg = 'Nothing to do. Specify at least one of "add" or "delete".'
|
||||||
self.assert_json_error(result, msg)
|
self.assert_json_error(result, msg)
|
||||||
|
|
||||||
# Test when user not a member of user group tries to remove members
|
|
||||||
self.logout()
|
|
||||||
self.login_user(cordelia)
|
|
||||||
params = {"delete": orjson.dumps([hamlet.id]).decode()}
|
|
||||||
result = self.client_post(f"/json/user_groups/{user_group.id}/members", info=params)
|
|
||||||
self.assert_json_error(result, "Insufficient permission")
|
|
||||||
self.assertEqual(UserGroupMembership.objects.count(), 4)
|
|
||||||
|
|
||||||
self.logout()
|
|
||||||
# Test when organization admin tries to remove members from group
|
|
||||||
iago = self.example_user("iago")
|
|
||||||
self.login_user(iago)
|
|
||||||
result = self.client_post(f"/json/user_groups/{user_group.id}/members", info=params)
|
|
||||||
self.assert_json_success(result)
|
|
||||||
self.assertEqual(UserGroupMembership.objects.count(), 3)
|
|
||||||
members = get_memberships_of_users(user_group, [hamlet, othello, aaron])
|
|
||||||
self.assert_length(members, 1)
|
|
||||||
|
|
||||||
def test_mentions(self) -> None:
|
def test_mentions(self) -> None:
|
||||||
cordelia = self.example_user("cordelia")
|
cordelia = self.example_user("cordelia")
|
||||||
hamlet = self.example_user("hamlet")
|
hamlet = self.example_user("hamlet")
|
||||||
@@ -436,82 +298,311 @@ class UserGroupAPITestCase(ZulipTestCase):
|
|||||||
um = most_recent_usermessage(user)
|
um = most_recent_usermessage(user)
|
||||||
self.assertFalse(um.flags.mentioned)
|
self.assertFalse(um.flags.mentioned)
|
||||||
|
|
||||||
def test_only_admin_manage_groups(self) -> None:
|
def test_user_group_edit_policy_for_creating_and_deleting_user_group(self) -> None:
|
||||||
iago = self.example_user("iago")
|
|
||||||
hamlet = self.example_user("hamlet")
|
hamlet = self.example_user("hamlet")
|
||||||
cordelia = self.example_user("cordelia")
|
|
||||||
self.login_user(iago)
|
|
||||||
do_set_realm_property(
|
|
||||||
iago.realm,
|
|
||||||
"user_group_edit_policy",
|
|
||||||
Realm.USER_GROUP_EDIT_POLICY_ADMINS,
|
|
||||||
acting_user=None,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
def check_create_user_group(acting_user: str, error_msg: Optional[str] = None) -> None:
|
||||||
|
self.login(acting_user)
|
||||||
params = {
|
params = {
|
||||||
"name": "support",
|
"name": "support",
|
||||||
"members": orjson.dumps([iago.id, hamlet.id]).decode(),
|
"members": orjson.dumps([hamlet.id]).decode(),
|
||||||
|
"description": "Support Team",
|
||||||
|
}
|
||||||
|
result = self.client_post("/json/user_groups/create", info=params)
|
||||||
|
if error_msg is None:
|
||||||
|
self.assert_json_success(result)
|
||||||
|
# One group already exists in the test database.
|
||||||
|
self.assert_length(UserGroup.objects.all(), 2)
|
||||||
|
else:
|
||||||
|
self.assert_json_error(result, error_msg)
|
||||||
|
|
||||||
|
def check_delete_user_group(acting_user: str, error_msg: Optional[str] = None) -> None:
|
||||||
|
self.login(acting_user)
|
||||||
|
user_group = UserGroup.objects.get(name="support")
|
||||||
|
result = self.client_delete(f"/json/user_groups/{user_group.id}")
|
||||||
|
if error_msg is None:
|
||||||
|
self.assert_json_success(result)
|
||||||
|
self.assert_length(UserGroup.objects.all(), 1)
|
||||||
|
else:
|
||||||
|
self.assert_json_error(result, error_msg)
|
||||||
|
|
||||||
|
realm = hamlet.realm
|
||||||
|
|
||||||
|
# Check only admins are allowed to create/delete user group. Admins are allowed even if
|
||||||
|
# they are not a member of the group.
|
||||||
|
do_set_realm_property(
|
||||||
|
realm,
|
||||||
|
"user_group_edit_policy",
|
||||||
|
Realm.POLICY_ADMINS_ONLY,
|
||||||
|
acting_user=None,
|
||||||
|
)
|
||||||
|
check_create_user_group("shiva", "Insufficient permission")
|
||||||
|
check_create_user_group("iago")
|
||||||
|
|
||||||
|
check_delete_user_group("shiva", "Insufficient permission")
|
||||||
|
check_delete_user_group("iago")
|
||||||
|
|
||||||
|
# Check moderators are allowed to create/delete user group but not members. Moderators are
|
||||||
|
# allowed even if they are not a member of the group.
|
||||||
|
do_set_realm_property(
|
||||||
|
realm,
|
||||||
|
"user_group_edit_policy",
|
||||||
|
Realm.POLICY_MODERATORS_ONLY,
|
||||||
|
acting_user=None,
|
||||||
|
)
|
||||||
|
check_create_user_group("cordelia", "Insufficient permission")
|
||||||
|
check_create_user_group("shiva")
|
||||||
|
|
||||||
|
check_delete_user_group("hamlet", "Insufficient permission")
|
||||||
|
check_delete_user_group("shiva")
|
||||||
|
|
||||||
|
# Check only members are allowed to create the user group and they are allowed to delete
|
||||||
|
# a user group only if they are a member of that group.
|
||||||
|
do_set_realm_property(
|
||||||
|
realm,
|
||||||
|
"user_group_edit_policy",
|
||||||
|
Realm.POLICY_MEMBERS_ONLY,
|
||||||
|
acting_user=None,
|
||||||
|
)
|
||||||
|
check_create_user_group("polonius", "Not allowed for guest users")
|
||||||
|
check_create_user_group("cordelia")
|
||||||
|
|
||||||
|
check_delete_user_group("polonius", "Not allowed for guest users")
|
||||||
|
check_delete_user_group("cordelia", "Insufficient permission")
|
||||||
|
check_delete_user_group("hamlet")
|
||||||
|
|
||||||
|
# Check only full members are allowed to create the user group and they are allowed to delete
|
||||||
|
# a user group only if they are a member of that group.
|
||||||
|
do_set_realm_property(
|
||||||
|
realm,
|
||||||
|
"user_group_edit_policy",
|
||||||
|
Realm.POLICY_FULL_MEMBERS_ONLY,
|
||||||
|
acting_user=None,
|
||||||
|
)
|
||||||
|
cordelia = self.example_user("cordelia")
|
||||||
|
do_set_realm_property(realm, "waiting_period_threshold", 10, acting_user=None)
|
||||||
|
|
||||||
|
cordelia.date_joined = timezone_now() - timedelta(days=9)
|
||||||
|
cordelia.save()
|
||||||
|
check_create_user_group("cordelia", "Insufficient permission")
|
||||||
|
|
||||||
|
cordelia.date_joined = timezone_now() - timedelta(days=11)
|
||||||
|
cordelia.save()
|
||||||
|
check_create_user_group("cordelia")
|
||||||
|
|
||||||
|
hamlet.date_joined = timezone_now() - timedelta(days=9)
|
||||||
|
hamlet.save()
|
||||||
|
|
||||||
|
check_delete_user_group("cordelia", "Insufficient permission")
|
||||||
|
check_delete_user_group("hamlet", "Insufficient permission")
|
||||||
|
|
||||||
|
hamlet.date_joined = timezone_now() - timedelta(days=11)
|
||||||
|
hamlet.save()
|
||||||
|
check_delete_user_group("hamlet")
|
||||||
|
|
||||||
|
def test_user_group_edit_policy_for_updating_user_groups(self) -> None:
|
||||||
|
othello = self.example_user("othello")
|
||||||
|
self.login("othello")
|
||||||
|
params = {
|
||||||
|
"name": "support",
|
||||||
|
"members": orjson.dumps([othello.id]).decode(),
|
||||||
"description": "Support team",
|
"description": "Support team",
|
||||||
}
|
}
|
||||||
|
self.client_post("/json/user_groups/create", info=params)
|
||||||
result = self.client_post("/json/user_groups/create", info=params)
|
|
||||||
self.assert_json_success(result)
|
|
||||||
user_group = UserGroup.objects.get(name="support")
|
user_group = UserGroup.objects.get(name="support")
|
||||||
|
|
||||||
# Test add member
|
def check_update_user_group(
|
||||||
params = {"add": orjson.dumps([cordelia.id]).decode()}
|
new_name: str,
|
||||||
result = self.client_post(f"/json/user_groups/{user_group.id}/members", info=params)
|
new_description: str,
|
||||||
self.assert_json_success(result)
|
acting_user: str,
|
||||||
|
error_msg: Optional[str] = None,
|
||||||
# Test remove member
|
) -> None:
|
||||||
params = {"delete": orjson.dumps([cordelia.id]).decode()}
|
self.login(acting_user)
|
||||||
result = self.client_post(f"/json/user_groups/{user_group.id}/members", info=params)
|
|
||||||
self.assert_json_success(result)
|
|
||||||
|
|
||||||
# Test changing groups name
|
|
||||||
params = {
|
params = {
|
||||||
"name": "help",
|
"name": new_name,
|
||||||
"description": "Troubleshooting",
|
"description": new_description,
|
||||||
}
|
}
|
||||||
result = self.client_patch(f"/json/user_groups/{user_group.id}", info=params)
|
result = self.client_patch(f"/json/user_groups/{user_group.id}", info=params)
|
||||||
|
if error_msg is None:
|
||||||
self.assert_json_success(result)
|
self.assert_json_success(result)
|
||||||
|
else:
|
||||||
|
self.assert_json_error(result, error_msg)
|
||||||
|
|
||||||
# Test delete a group
|
realm = othello.realm
|
||||||
result = self.client_delete(f"/json/user_groups/{user_group.id}")
|
|
||||||
self.assert_json_success(result)
|
|
||||||
|
|
||||||
user_group = create_user_group(
|
# Check only admins are allowed to update user group. Admins are allowed even if
|
||||||
name="support",
|
# they are not a member of the group.
|
||||||
members=[hamlet, iago],
|
do_set_realm_property(
|
||||||
realm=iago.realm,
|
realm,
|
||||||
|
"user_group_edit_policy",
|
||||||
|
Realm.POLICY_ADMINS_ONLY,
|
||||||
|
acting_user=None,
|
||||||
)
|
)
|
||||||
|
check_update_user_group("help", "Troubleshooting team", "shiva", "Insufficient permission")
|
||||||
|
check_update_user_group("help", "Troubleshooting team", "iago")
|
||||||
|
|
||||||
self.logout()
|
# Check moderators are allowed to update user group but not members. Moderators are
|
||||||
|
# allowed even if they are not a member of the group.
|
||||||
|
do_set_realm_property(
|
||||||
|
realm,
|
||||||
|
"user_group_edit_policy",
|
||||||
|
Realm.POLICY_MODERATORS_ONLY,
|
||||||
|
acting_user=None,
|
||||||
|
)
|
||||||
|
check_update_user_group("support", "Support team", "othello", "Insufficient permission")
|
||||||
|
check_update_user_group("support", "Support team", "iago")
|
||||||
|
|
||||||
self.login("hamlet")
|
# Check only members are allowed to update the user group and only if belong to the
|
||||||
|
# user group.
|
||||||
|
do_set_realm_property(
|
||||||
|
realm,
|
||||||
|
"user_group_edit_policy",
|
||||||
|
Realm.POLICY_MEMBERS_ONLY,
|
||||||
|
acting_user=None,
|
||||||
|
)
|
||||||
|
check_update_user_group(
|
||||||
|
"help", "Troubleshooting team", "polonius", "Not allowed for guest users"
|
||||||
|
)
|
||||||
|
check_update_user_group(
|
||||||
|
"help",
|
||||||
|
"Troubleshooting team",
|
||||||
|
"cordelia",
|
||||||
|
"Insufficient permission",
|
||||||
|
)
|
||||||
|
check_update_user_group("help", "Troubleshooting team", "othello")
|
||||||
|
|
||||||
# Test creating a group
|
# Check only full members are allowed to update the user group and only if belong to the
|
||||||
params = {
|
# user group.
|
||||||
"name": "support2",
|
do_set_realm_property(
|
||||||
"members": orjson.dumps([hamlet.id]).decode(),
|
realm, "user_group_edit_policy", Realm.POLICY_FULL_MEMBERS_ONLY, acting_user=None
|
||||||
"description": "Support team",
|
)
|
||||||
}
|
do_set_realm_property(realm, "waiting_period_threshold", 10, acting_user=None)
|
||||||
result = self.client_post("/json/user_groups/create", info=params)
|
othello = self.example_user("othello")
|
||||||
self.assert_json_error(result, "Must be an organization administrator")
|
othello.date_joined = timezone_now() - timedelta(days=9)
|
||||||
|
othello.save()
|
||||||
|
|
||||||
# Test add member
|
cordelia = self.example_user("cordelia")
|
||||||
params = {"add": orjson.dumps([cordelia.id]).decode()}
|
cordelia.date_joined = timezone_now() - timedelta(days=11)
|
||||||
|
cordelia.save()
|
||||||
|
check_update_user_group(
|
||||||
|
"support",
|
||||||
|
"Support team",
|
||||||
|
"cordelia",
|
||||||
|
"Insufficient permission",
|
||||||
|
)
|
||||||
|
check_update_user_group("support", "Support team", "othello", "Insufficient permission")
|
||||||
|
|
||||||
|
othello.date_joined = timezone_now() - timedelta(days=11)
|
||||||
|
othello.save()
|
||||||
|
check_update_user_group("support", "Support team", "othello")
|
||||||
|
|
||||||
|
def test_user_group_edit_policy_for_updating_members(self) -> None:
|
||||||
|
user_group = self.create_user_group_for_test("support")
|
||||||
|
aaron = self.example_user("aaron")
|
||||||
|
othello = self.example_user("othello")
|
||||||
|
cordelia = self.example_user("cordelia")
|
||||||
|
|
||||||
|
def check_adding_members_to_group(
|
||||||
|
acting_user: str, error_msg: Optional[str] = None
|
||||||
|
) -> None:
|
||||||
|
self.login(acting_user)
|
||||||
|
params = {"add": orjson.dumps([aaron.id]).decode()}
|
||||||
result = self.client_post(f"/json/user_groups/{user_group.id}/members", info=params)
|
result = self.client_post(f"/json/user_groups/{user_group.id}/members", info=params)
|
||||||
self.assert_json_error(result, "Must be an organization administrator")
|
if error_msg is None:
|
||||||
|
self.assert_json_success(result)
|
||||||
|
self.assertEqual(UserGroupMembership.objects.count(), 4)
|
||||||
|
members = get_memberships_of_users(user_group, [aaron, othello])
|
||||||
|
self.assert_length(members, 2)
|
||||||
|
else:
|
||||||
|
self.assert_json_error(result, error_msg)
|
||||||
|
|
||||||
# Test delete a group
|
def check_removing_members_from_group(
|
||||||
result = self.client_delete(f"/json/user_groups/{user_group.id}")
|
acting_user: str, error_msg: Optional[str] = None
|
||||||
self.assert_json_error(result, "Must be an organization administrator")
|
) -> None:
|
||||||
|
self.login(acting_user)
|
||||||
|
params = {"delete": orjson.dumps([aaron.id]).decode()}
|
||||||
|
result = self.client_post(f"/json/user_groups/{user_group.id}/members", info=params)
|
||||||
|
if error_msg is None:
|
||||||
|
self.assert_json_success(result)
|
||||||
|
self.assertEqual(UserGroupMembership.objects.count(), 3)
|
||||||
|
members = get_memberships_of_users(user_group, [aaron, othello])
|
||||||
|
self.assert_length(members, 1)
|
||||||
|
else:
|
||||||
|
self.assert_json_error(result, error_msg)
|
||||||
|
|
||||||
# Test changing groups name
|
realm = get_realm("zulip")
|
||||||
params = {
|
# Check only admins are allowed to add/remove users from the group. Admins are allowed even if
|
||||||
"name": "help",
|
# they are not a member of the group.
|
||||||
"description": "Troubleshooting",
|
do_set_realm_property(
|
||||||
}
|
realm,
|
||||||
result = self.client_patch(f"/json/user_groups/{user_group.id}", info=params)
|
"user_group_edit_policy",
|
||||||
self.assert_json_error(result, "Must be an organization administrator")
|
Realm.POLICY_ADMINS_ONLY,
|
||||||
|
acting_user=None,
|
||||||
|
)
|
||||||
|
check_adding_members_to_group("shiva", "Insufficient permission")
|
||||||
|
check_adding_members_to_group("iago")
|
||||||
|
|
||||||
|
check_removing_members_from_group("shiva", "Insufficient permission")
|
||||||
|
check_removing_members_from_group("iago")
|
||||||
|
|
||||||
|
# Check moderators are allowed to add/remove users from the group but not members. Moderators are
|
||||||
|
# allowed even if they are not a member of the group.
|
||||||
|
do_set_realm_property(
|
||||||
|
realm,
|
||||||
|
"user_group_edit_policy",
|
||||||
|
Realm.POLICY_MODERATORS_ONLY,
|
||||||
|
acting_user=None,
|
||||||
|
)
|
||||||
|
check_adding_members_to_group("cordelia", "Insufficient permission")
|
||||||
|
check_adding_members_to_group("shiva")
|
||||||
|
|
||||||
|
check_removing_members_from_group("hamlet", "Insufficient permission")
|
||||||
|
check_removing_members_from_group("shiva")
|
||||||
|
|
||||||
|
# Check only members are allowed to add/remove users in the group and only if belong to the
|
||||||
|
# user group.
|
||||||
|
do_set_realm_property(
|
||||||
|
realm,
|
||||||
|
"user_group_edit_policy",
|
||||||
|
Realm.POLICY_MEMBERS_ONLY,
|
||||||
|
acting_user=None,
|
||||||
|
)
|
||||||
|
check_adding_members_to_group("polonius", "Not allowed for guest users")
|
||||||
|
check_adding_members_to_group("cordelia", "Insufficient permission")
|
||||||
|
check_adding_members_to_group("othello")
|
||||||
|
|
||||||
|
check_removing_members_from_group("polonius", "Not allowed for guest users")
|
||||||
|
check_removing_members_from_group("cordelia", "Insufficient permission")
|
||||||
|
check_removing_members_from_group("othello")
|
||||||
|
|
||||||
|
# Check only full members are allowed to add/remove users in the group and only if belong to the
|
||||||
|
# user group.
|
||||||
|
do_set_realm_property(
|
||||||
|
realm,
|
||||||
|
"user_group_edit_policy",
|
||||||
|
Realm.POLICY_FULL_MEMBERS_ONLY,
|
||||||
|
acting_user=None,
|
||||||
|
)
|
||||||
|
do_set_realm_property(realm, "waiting_period_threshold", 10, acting_user=None)
|
||||||
|
|
||||||
|
othello.date_joined = timezone_now() - timedelta(days=9)
|
||||||
|
othello.save()
|
||||||
|
check_adding_members_to_group("cordelia", "Insufficient permission")
|
||||||
|
|
||||||
|
cordelia.date_joined = timezone_now() - timedelta(days=11)
|
||||||
|
cordelia.save()
|
||||||
|
check_adding_members_to_group("cordelia", "Insufficient permission")
|
||||||
|
|
||||||
|
othello.date_joined = timezone_now() - timedelta(days=11)
|
||||||
|
othello.save()
|
||||||
|
check_adding_members_to_group("othello")
|
||||||
|
|
||||||
|
othello.date_joined = timezone_now() - timedelta(days=9)
|
||||||
|
othello.save()
|
||||||
|
|
||||||
|
check_removing_members_from_group("cordelia", "Insufficient permission")
|
||||||
|
check_removing_members_from_group("othello", "Insufficient permission")
|
||||||
|
|
||||||
|
othello.date_joined = timezone_now() - timedelta(days=11)
|
||||||
|
othello.save()
|
||||||
|
check_removing_members_from_group("othello")
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ def update_realm(
|
|||||||
json_validator=check_int_in(Realm.COMMON_POLICY_TYPES), default=None
|
json_validator=check_int_in(Realm.COMMON_POLICY_TYPES), default=None
|
||||||
),
|
),
|
||||||
user_group_edit_policy: Optional[int] = REQ(
|
user_group_edit_policy: Optional[int] = REQ(
|
||||||
json_validator=check_int_in(Realm.USER_GROUP_EDIT_POLICY_TYPES), default=None
|
json_validator=check_int_in(Realm.COMMON_POLICY_TYPES), default=None
|
||||||
),
|
),
|
||||||
private_message_policy: Optional[int] = REQ(
|
private_message_policy: Optional[int] = REQ(
|
||||||
json_validator=check_int_in(Realm.PRIVATE_MESSAGE_POLICY_TYPES), default=None
|
json_validator=check_int_in(Realm.PRIVATE_MESSAGE_POLICY_TYPES), default=None
|
||||||
|
|||||||
Reference in New Issue
Block a user