|
|
|
|
@@ -11,8 +11,11 @@ from zerver.actions.create_realm import do_create_realm
|
|
|
|
|
from zerver.actions.realm_settings import do_set_realm_property
|
|
|
|
|
from zerver.actions.user_groups import (
|
|
|
|
|
add_subgroups_to_user_group,
|
|
|
|
|
bulk_add_members_to_user_groups,
|
|
|
|
|
bulk_remove_members_from_user_groups,
|
|
|
|
|
check_add_user_group,
|
|
|
|
|
create_user_group_in_database,
|
|
|
|
|
do_change_user_group_permission_setting,
|
|
|
|
|
promote_new_full_members,
|
|
|
|
|
)
|
|
|
|
|
from zerver.actions.users import do_deactivate_user
|
|
|
|
|
@@ -28,6 +31,7 @@ from zerver.lib.user_groups import (
|
|
|
|
|
get_recursive_membership_groups,
|
|
|
|
|
get_recursive_strict_subgroups,
|
|
|
|
|
get_recursive_subgroups,
|
|
|
|
|
get_role_based_system_groups_dict,
|
|
|
|
|
get_subgroup_ids,
|
|
|
|
|
get_user_group_member_ids,
|
|
|
|
|
has_user_group_access,
|
|
|
|
|
@@ -38,6 +42,7 @@ from zerver.lib.user_groups import (
|
|
|
|
|
from zerver.models import (
|
|
|
|
|
GroupGroupMembership,
|
|
|
|
|
NamedUserGroup,
|
|
|
|
|
Realm,
|
|
|
|
|
UserGroup,
|
|
|
|
|
UserGroupMembership,
|
|
|
|
|
UserProfile,
|
|
|
|
|
@@ -628,9 +633,9 @@ class UserGroupAPITestCase(UserGroupTestCase):
|
|
|
|
|
NamedUserGroup.objects.filter(realm=user_profile.realm).count(),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
def test_can_edit_user_groups(self) -> None:
|
|
|
|
|
def test_can_edit_all_user_groups(self) -> None:
|
|
|
|
|
def validation_func(user_profile: UserProfile) -> bool:
|
|
|
|
|
return user_profile.can_edit_user_groups()
|
|
|
|
|
return user_profile.can_edit_all_user_groups()
|
|
|
|
|
|
|
|
|
|
self.check_has_permission_policies("user_group_edit_policy", validation_func)
|
|
|
|
|
|
|
|
|
|
@@ -1386,7 +1391,7 @@ class UserGroupAPITestCase(UserGroupTestCase):
|
|
|
|
|
othello.save()
|
|
|
|
|
check_create_user_group("othello")
|
|
|
|
|
|
|
|
|
|
def test_user_group_edit_policy_for_deleting_user_group(self) -> None:
|
|
|
|
|
def test_realm_level_policy_for_deleting_user_group(self) -> None:
|
|
|
|
|
hamlet = self.example_user("hamlet")
|
|
|
|
|
realm = hamlet.realm
|
|
|
|
|
|
|
|
|
|
@@ -1465,7 +1470,95 @@ class UserGroupAPITestCase(UserGroupTestCase):
|
|
|
|
|
othello.save()
|
|
|
|
|
check_delete_user_group("othello")
|
|
|
|
|
|
|
|
|
|
def test_user_group_edit_policy_for_updating_user_groups(self) -> None:
|
|
|
|
|
def test_group_level_setting_for_deleting_user_groups(self) -> None:
|
|
|
|
|
othello = self.example_user("othello")
|
|
|
|
|
realm = othello.realm
|
|
|
|
|
|
|
|
|
|
hamlet = self.example_user("hamlet")
|
|
|
|
|
leadership_group = check_add_user_group(
|
|
|
|
|
get_realm("zulip"), "leadership", [hamlet], acting_user=hamlet
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
def check_delete_user_group(acting_user: str, error_msg: str | None = None) -> None:
|
|
|
|
|
user_group = NamedUserGroup.objects.get(name="support")
|
|
|
|
|
with transaction.atomic():
|
|
|
|
|
result = self.api_delete(
|
|
|
|
|
self.example_user(acting_user), f"/api/v1/user_groups/{user_group.id}"
|
|
|
|
|
)
|
|
|
|
|
if error_msg is None:
|
|
|
|
|
self.assert_json_success(result)
|
|
|
|
|
else:
|
|
|
|
|
self.assert_json_error(result, error_msg)
|
|
|
|
|
|
|
|
|
|
do_set_realm_property(
|
|
|
|
|
realm,
|
|
|
|
|
"user_group_edit_policy",
|
|
|
|
|
Realm.POLICY_NOBODY,
|
|
|
|
|
acting_user=None,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
support_group = check_add_user_group(
|
|
|
|
|
get_realm("zulip"), "support", [othello], acting_user=None
|
|
|
|
|
)
|
|
|
|
|
# Default value of can_manage_group is "Nobody" system group.
|
|
|
|
|
check_delete_user_group("desdemona", "Insufficient permission")
|
|
|
|
|
check_delete_user_group("othello", "Insufficient permission")
|
|
|
|
|
|
|
|
|
|
system_group_dict = get_role_based_system_groups_dict(realm)
|
|
|
|
|
owners_group = system_group_dict[SystemGroups.OWNERS]
|
|
|
|
|
do_change_user_group_permission_setting(
|
|
|
|
|
support_group, "can_manage_group", owners_group, acting_user=None
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
check_delete_user_group("iago", "Insufficient permission")
|
|
|
|
|
check_delete_user_group("desdemona")
|
|
|
|
|
|
|
|
|
|
check_add_user_group(
|
|
|
|
|
get_realm("zulip"),
|
|
|
|
|
"support",
|
|
|
|
|
[othello],
|
|
|
|
|
"",
|
|
|
|
|
{"can_manage_group": system_group_dict[SystemGroups.MEMBERS]},
|
|
|
|
|
acting_user=None,
|
|
|
|
|
)
|
|
|
|
|
check_delete_user_group("polonius", "Not allowed for guest users")
|
|
|
|
|
check_delete_user_group("cordelia")
|
|
|
|
|
|
|
|
|
|
setting_group = self.create_or_update_anonymous_group_for_setting(
|
|
|
|
|
[self.example_user("cordelia")], [leadership_group, owners_group]
|
|
|
|
|
)
|
|
|
|
|
check_add_user_group(
|
|
|
|
|
get_realm("zulip"),
|
|
|
|
|
"support",
|
|
|
|
|
[othello],
|
|
|
|
|
"",
|
|
|
|
|
{"can_manage_group": setting_group},
|
|
|
|
|
acting_user=None,
|
|
|
|
|
)
|
|
|
|
|
check_delete_user_group("iago", "Insufficient permission")
|
|
|
|
|
check_delete_user_group("hamlet")
|
|
|
|
|
|
|
|
|
|
check_add_user_group(
|
|
|
|
|
get_realm("zulip"),
|
|
|
|
|
"support",
|
|
|
|
|
[othello],
|
|
|
|
|
"",
|
|
|
|
|
{"can_manage_group": setting_group},
|
|
|
|
|
acting_user=None,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
check_delete_user_group("cordelia")
|
|
|
|
|
check_add_user_group(
|
|
|
|
|
get_realm("zulip"),
|
|
|
|
|
"support",
|
|
|
|
|
[othello],
|
|
|
|
|
"",
|
|
|
|
|
{"can_manage_group": setting_group},
|
|
|
|
|
acting_user=None,
|
|
|
|
|
)
|
|
|
|
|
check_delete_user_group("desdemona")
|
|
|
|
|
|
|
|
|
|
def test_realm_level_setting_for_updating_user_groups(self) -> None:
|
|
|
|
|
othello = self.example_user("othello")
|
|
|
|
|
self.login("othello")
|
|
|
|
|
params = {
|
|
|
|
|
@@ -1482,7 +1575,6 @@ class UserGroupAPITestCase(UserGroupTestCase):
|
|
|
|
|
acting_user: str,
|
|
|
|
|
error_msg: str | None = None,
|
|
|
|
|
) -> None:
|
|
|
|
|
self.login(acting_user)
|
|
|
|
|
params = {
|
|
|
|
|
"name": new_name,
|
|
|
|
|
"description": new_description,
|
|
|
|
|
@@ -1491,7 +1583,9 @@ class UserGroupAPITestCase(UserGroupTestCase):
|
|
|
|
|
self.assertNotEqual(user_group.name, new_name)
|
|
|
|
|
self.assertNotEqual(user_group.description, new_description)
|
|
|
|
|
|
|
|
|
|
result = self.client_patch(f"/json/user_groups/{user_group.id}", info=params)
|
|
|
|
|
result = self.api_patch(
|
|
|
|
|
self.example_user(acting_user), f"/api/v1/user_groups/{user_group.id}", info=params
|
|
|
|
|
)
|
|
|
|
|
if error_msg is None:
|
|
|
|
|
self.assert_json_success(result)
|
|
|
|
|
user_group.refresh_from_db()
|
|
|
|
|
@@ -1568,17 +1662,105 @@ class UserGroupAPITestCase(UserGroupTestCase):
|
|
|
|
|
othello.save()
|
|
|
|
|
check_update_user_group("support", "Support team", "othello")
|
|
|
|
|
|
|
|
|
|
def test_user_group_edit_policy_for_updating_members(self) -> None:
|
|
|
|
|
def test_group_level_setting_for_updating_user_groups(self) -> None:
|
|
|
|
|
othello = self.example_user("othello")
|
|
|
|
|
iago = self.example_user("iago")
|
|
|
|
|
user_group = check_add_user_group(
|
|
|
|
|
get_realm("zulip"), "support", [othello, iago], acting_user=othello
|
|
|
|
|
)
|
|
|
|
|
hamlet = self.example_user("hamlet")
|
|
|
|
|
leadership_group = check_add_user_group(
|
|
|
|
|
get_realm("zulip"), "leadership", [hamlet], acting_user=hamlet
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
def check_update_user_group(
|
|
|
|
|
new_name: str,
|
|
|
|
|
new_description: str,
|
|
|
|
|
acting_user: str,
|
|
|
|
|
error_msg: str | None = None,
|
|
|
|
|
) -> None:
|
|
|
|
|
params = {
|
|
|
|
|
"name": new_name,
|
|
|
|
|
"description": new_description,
|
|
|
|
|
}
|
|
|
|
|
# Ensure that this update request is not a no-op.
|
|
|
|
|
self.assertNotEqual(user_group.name, new_name)
|
|
|
|
|
self.assertNotEqual(user_group.description, new_description)
|
|
|
|
|
|
|
|
|
|
result = self.api_patch(
|
|
|
|
|
self.example_user(acting_user), f"/api/v1/user_groups/{user_group.id}", info=params
|
|
|
|
|
)
|
|
|
|
|
if error_msg is None:
|
|
|
|
|
self.assert_json_success(result)
|
|
|
|
|
user_group.refresh_from_db()
|
|
|
|
|
self.assertEqual(user_group.name, new_name)
|
|
|
|
|
self.assertEqual(user_group.description, new_description)
|
|
|
|
|
else:
|
|
|
|
|
self.assert_json_error(result, error_msg)
|
|
|
|
|
|
|
|
|
|
realm = othello.realm
|
|
|
|
|
|
|
|
|
|
do_set_realm_property(
|
|
|
|
|
realm,
|
|
|
|
|
"user_group_edit_policy",
|
|
|
|
|
Realm.POLICY_NOBODY,
|
|
|
|
|
acting_user=None,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Default value of can_manage_group is "Nobody" system group.
|
|
|
|
|
check_update_user_group("help", "Troubleshooting team", "iago", "Insufficient permission")
|
|
|
|
|
check_update_user_group(
|
|
|
|
|
"help", "Troubleshooting team", "othello", "Insufficient permission"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
system_group_dict = get_role_based_system_groups_dict(realm)
|
|
|
|
|
owners_group = system_group_dict[SystemGroups.OWNERS]
|
|
|
|
|
do_change_user_group_permission_setting(
|
|
|
|
|
user_group, "can_manage_group", owners_group, acting_user=None
|
|
|
|
|
)
|
|
|
|
|
check_update_user_group("help", "Troubleshooting team", "iago", "Insufficient permission")
|
|
|
|
|
check_update_user_group("help", "Troubleshooting team", "desdemona")
|
|
|
|
|
|
|
|
|
|
user_group.can_manage_group = system_group_dict[SystemGroups.MEMBERS]
|
|
|
|
|
user_group.save()
|
|
|
|
|
check_update_user_group(
|
|
|
|
|
"support", "Support team", "polonius", "Not allowed for guest users"
|
|
|
|
|
)
|
|
|
|
|
check_update_user_group(
|
|
|
|
|
"support",
|
|
|
|
|
"Support team",
|
|
|
|
|
"cordelia",
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
setting_group = self.create_or_update_anonymous_group_for_setting(
|
|
|
|
|
[self.example_user("cordelia")], [leadership_group, owners_group]
|
|
|
|
|
)
|
|
|
|
|
do_change_user_group_permission_setting(
|
|
|
|
|
user_group, "can_manage_group", setting_group, acting_user=None
|
|
|
|
|
)
|
|
|
|
|
check_update_user_group("help", "Troubleshooting team", "iago", "Insufficient permission")
|
|
|
|
|
check_update_user_group("help", "Troubleshooting team", "hamlet")
|
|
|
|
|
check_update_user_group(
|
|
|
|
|
"support",
|
|
|
|
|
"Support team",
|
|
|
|
|
"cordelia",
|
|
|
|
|
)
|
|
|
|
|
check_update_user_group("help", "Troubleshooting team", "desdemona")
|
|
|
|
|
|
|
|
|
|
def test_realm_level_setting_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: str | None = None) -> None:
|
|
|
|
|
self.login(acting_user)
|
|
|
|
|
params = {"add": orjson.dumps([aaron.id]).decode()}
|
|
|
|
|
self.assert_user_membership(user_group, [othello])
|
|
|
|
|
result = self.client_post(f"/json/user_groups/{user_group.id}/members", info=params)
|
|
|
|
|
result = self.api_post(
|
|
|
|
|
self.example_user(acting_user),
|
|
|
|
|
f"/api/v1/user_groups/{user_group.id}/members",
|
|
|
|
|
info=params,
|
|
|
|
|
)
|
|
|
|
|
if error_msg is None:
|
|
|
|
|
self.assert_json_success(result)
|
|
|
|
|
self.assert_user_membership(user_group, [aaron, othello])
|
|
|
|
|
@@ -1588,10 +1770,13 @@ class UserGroupAPITestCase(UserGroupTestCase):
|
|
|
|
|
def check_removing_members_from_group(
|
|
|
|
|
acting_user: str, error_msg: str | None = None
|
|
|
|
|
) -> None:
|
|
|
|
|
self.login(acting_user)
|
|
|
|
|
params = {"delete": orjson.dumps([aaron.id]).decode()}
|
|
|
|
|
self.assert_user_membership(user_group, [aaron, othello])
|
|
|
|
|
result = self.client_post(f"/json/user_groups/{user_group.id}/members", info=params)
|
|
|
|
|
result = self.api_post(
|
|
|
|
|
self.example_user(acting_user),
|
|
|
|
|
f"/api/v1/user_groups/{user_group.id}/members",
|
|
|
|
|
info=params,
|
|
|
|
|
)
|
|
|
|
|
if error_msg is None:
|
|
|
|
|
self.assert_json_success(result)
|
|
|
|
|
self.assert_user_membership(user_group, [othello])
|
|
|
|
|
@@ -1675,6 +1860,108 @@ class UserGroupAPITestCase(UserGroupTestCase):
|
|
|
|
|
othello.save()
|
|
|
|
|
check_removing_members_from_group("othello")
|
|
|
|
|
|
|
|
|
|
def test_group_level_setting_for_updating_members(self) -> None:
|
|
|
|
|
othello = self.example_user("othello")
|
|
|
|
|
user_group = check_add_user_group(
|
|
|
|
|
get_realm("zulip"), "support", [othello], acting_user=None
|
|
|
|
|
)
|
|
|
|
|
hamlet = self.example_user("hamlet")
|
|
|
|
|
leadership_group = check_add_user_group(
|
|
|
|
|
get_realm("zulip"), "leadership", [hamlet], acting_user=None
|
|
|
|
|
)
|
|
|
|
|
aaron = self.example_user("aaron")
|
|
|
|
|
|
|
|
|
|
def check_adding_members_to_group(acting_user: str, error_msg: str | None = None) -> None:
|
|
|
|
|
params = {"add": orjson.dumps([aaron.id]).decode()}
|
|
|
|
|
self.assert_user_membership(user_group, [othello])
|
|
|
|
|
result = self.api_post(
|
|
|
|
|
self.example_user(acting_user),
|
|
|
|
|
f"/api/v1/user_groups/{user_group.id}/members",
|
|
|
|
|
info=params,
|
|
|
|
|
)
|
|
|
|
|
if error_msg is None:
|
|
|
|
|
self.assert_json_success(result)
|
|
|
|
|
self.assert_user_membership(user_group, [aaron, othello])
|
|
|
|
|
else:
|
|
|
|
|
self.assert_json_error(result, error_msg)
|
|
|
|
|
|
|
|
|
|
def check_removing_members_from_group(
|
|
|
|
|
acting_user: str, error_msg: str | None = None
|
|
|
|
|
) -> None:
|
|
|
|
|
params = {"delete": orjson.dumps([aaron.id]).decode()}
|
|
|
|
|
self.assert_user_membership(user_group, [aaron, othello])
|
|
|
|
|
result = self.api_post(
|
|
|
|
|
self.example_user(acting_user),
|
|
|
|
|
f"/api/v1/user_groups/{user_group.id}/members",
|
|
|
|
|
info=params,
|
|
|
|
|
)
|
|
|
|
|
if error_msg is None:
|
|
|
|
|
self.assert_json_success(result)
|
|
|
|
|
self.assert_user_membership(user_group, [othello])
|
|
|
|
|
else:
|
|
|
|
|
self.assert_json_error(result, error_msg)
|
|
|
|
|
|
|
|
|
|
realm = get_realm("zulip")
|
|
|
|
|
do_set_realm_property(
|
|
|
|
|
realm,
|
|
|
|
|
"user_group_edit_policy",
|
|
|
|
|
Realm.POLICY_NOBODY,
|
|
|
|
|
acting_user=None,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Default value of can_manage_group is "Nobody system group".
|
|
|
|
|
check_adding_members_to_group("iago", "Insufficient permission")
|
|
|
|
|
check_adding_members_to_group("othello", "Insufficient permission")
|
|
|
|
|
|
|
|
|
|
# Add aaron to group so that we can test the removal.
|
|
|
|
|
bulk_add_members_to_user_groups([user_group], [aaron.id], acting_user=None)
|
|
|
|
|
|
|
|
|
|
check_removing_members_from_group("iago", "Insufficient permission")
|
|
|
|
|
check_removing_members_from_group("othello", "Insufficient permission")
|
|
|
|
|
|
|
|
|
|
# Remove aaron from group to add them again in further tests.
|
|
|
|
|
bulk_remove_members_from_user_groups([user_group], [aaron.id], acting_user=None)
|
|
|
|
|
|
|
|
|
|
system_group_dict = get_role_based_system_groups_dict(realm)
|
|
|
|
|
owners_group = system_group_dict[SystemGroups.OWNERS]
|
|
|
|
|
do_change_user_group_permission_setting(
|
|
|
|
|
user_group, "can_manage_group", owners_group, acting_user=None
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
check_adding_members_to_group("iago", "Insufficient permission")
|
|
|
|
|
check_adding_members_to_group("desdemona")
|
|
|
|
|
|
|
|
|
|
check_removing_members_from_group("iago", "Insufficient permission")
|
|
|
|
|
check_removing_members_from_group("desdemona")
|
|
|
|
|
|
|
|
|
|
members_group = system_group_dict[SystemGroups.MEMBERS]
|
|
|
|
|
do_change_user_group_permission_setting(
|
|
|
|
|
user_group, "can_manage_group", members_group, acting_user=None
|
|
|
|
|
)
|
|
|
|
|
check_adding_members_to_group("polonius", "Not allowed for guest users")
|
|
|
|
|
check_adding_members_to_group("cordelia")
|
|
|
|
|
|
|
|
|
|
check_removing_members_from_group("polonius", "Not allowed for guest users")
|
|
|
|
|
check_removing_members_from_group("cordelia")
|
|
|
|
|
|
|
|
|
|
setting_group = self.create_or_update_anonymous_group_for_setting(
|
|
|
|
|
[self.example_user("cordelia")], [leadership_group, owners_group]
|
|
|
|
|
)
|
|
|
|
|
do_change_user_group_permission_setting(
|
|
|
|
|
user_group, "can_manage_group", setting_group, acting_user=None
|
|
|
|
|
)
|
|
|
|
|
check_adding_members_to_group("iago", "Insufficient permission")
|
|
|
|
|
check_adding_members_to_group("hamlet")
|
|
|
|
|
|
|
|
|
|
check_removing_members_from_group("iago", "Insufficient permission")
|
|
|
|
|
check_removing_members_from_group("hamlet")
|
|
|
|
|
|
|
|
|
|
check_adding_members_to_group("cordelia")
|
|
|
|
|
check_removing_members_from_group("cordelia")
|
|
|
|
|
|
|
|
|
|
check_adding_members_to_group("desdemona")
|
|
|
|
|
check_removing_members_from_group("desdemona")
|
|
|
|
|
|
|
|
|
|
def test_editing_system_user_groups(self) -> None:
|
|
|
|
|
desdemona = self.example_user("desdemona")
|
|
|
|
|
iago = self.example_user("iago")
|
|
|
|
|
|