tests: Move channel administering permission tests.

This commit moves tests to check permission for administering
streams as per can_administer_channel_group setting to
test_channel_permissions.py.
This commit is contained in:
Sahil Batra
2025-06-04 19:43:58 +05:30
committed by Tim Abbott
parent 7eadabe10a
commit 3f8518f9d1
2 changed files with 530 additions and 330 deletions

View File

@@ -1,16 +1,25 @@
from typing import TypedDict
import orjson
from typing_extensions import override
from zerver.actions.channel_folders import check_add_channel_folder
from zerver.actions.realm_settings import (
do_change_realm_permission_group_setting,
do_set_realm_property,
)
from zerver.actions.streams import do_change_stream_group_based_setting
from zerver.actions.streams import (
do_change_stream_group_based_setting,
do_change_stream_permission,
do_deactivate_stream,
)
from zerver.actions.user_groups import add_subgroups_to_user_group, check_add_user_group
from zerver.actions.users import do_change_user_role
from zerver.lib.streams import subscribed_to_stream
from zerver.lib.test_classes import ZulipTestCase
from zerver.lib.test_helpers import get_subscription
from zerver.lib.types import UserGroupMembersData
from zerver.lib.user_groups import get_group_setting_value_for_api
from zerver.models import NamedUserGroup, Recipient, Stream, Subscription, UserProfile
from zerver.models.groups import SystemGroups
from zerver.models.realms import get_realm
@@ -746,3 +755,506 @@ class ChannelSubscriptionPermissionTest(ZulipTestCase):
self.assert_json_success(result)
stream = get_stream("stream_name1", realm)
self.assertEqual(stream.message_retention_days, 2)
class PermissionCheckConfigDict(TypedDict):
setting_group: NamedUserGroup | UserGroupMembersData
users_with_permission: list[UserProfile]
users_without_permission: list[UserProfile]
class ChannelAdministerPermissionTest(ZulipTestCase):
@override
def setUp(self) -> None:
super().setUp()
self.realm = get_realm("zulip")
self.admin = self.example_user("iago")
self.moderator = self.example_user("shiva")
self.guest = self.example_user("polonius")
self.hamletcharacters_group = NamedUserGroup.objects.get(
name="hamletcharacters", realm=self.realm
)
self.moderators_group = NamedUserGroup.objects.get(
name=SystemGroups.MODERATORS, realm=self.realm, is_system_group=True
)
self.nobody_group = NamedUserGroup.objects.get(
name=SystemGroups.NOBODY, realm=self.realm, is_system_group=True
)
self.members_group = NamedUserGroup.objects.get(
name=SystemGroups.MEMBERS, realm=self.realm, is_system_group=True
)
def do_test_updating_channel(
self, stream: Stream, property_name: str, new_value: str | int | bool
) -> None:
hamlet = self.example_user("hamlet")
prospero = self.example_user("prospero")
# For some properties, name of the field in Stream model
# is different from parameter name used in API request.
api_parameter_name_dict = dict(
name="new_name",
deactivated="is_archived",
)
api_parameter_name = property_name
if property_name in api_parameter_name_dict:
api_parameter_name = api_parameter_name_dict[property_name]
data = {}
if not isinstance(new_value, str):
data[api_parameter_name] = orjson.dumps(new_value).decode()
else:
data[api_parameter_name] = new_value
default_error_msg = "You do not have permission to administer this channel."
def check_channel_property_update(
user: UserProfile, allow_fail: bool = False, error_msg: str = default_error_msg
) -> None:
old_value = getattr(stream, property_name)
result = self.api_patch(user, f"/api/v1/streams/{stream.id}", info=data)
if allow_fail:
self.assert_json_error(result, error_msg)
return
self.assert_json_success(result)
stream.refresh_from_db()
self.assertEqual(getattr(stream, property_name), new_value)
# Reset to original value.
setattr(stream, property_name, old_value)
stream.save(update_fields=[property_name])
anonymous_group_dict = UserGroupMembersData(
direct_members=[prospero.id, self.guest.id], direct_subgroups=[]
)
group_permission_checks: list[PermissionCheckConfigDict] = [
# Check admin can always administer channel.
PermissionCheckConfigDict(
setting_group=self.nobody_group,
users_without_permission=[self.moderator],
users_with_permission=[self.admin],
),
# Check case when can_administer_channel_group is set to a system group.
PermissionCheckConfigDict(
setting_group=self.moderators_group,
users_without_permission=[hamlet],
users_with_permission=[self.moderator],
),
# Check case when can_administer_channel_group is set to a user-defined group.
PermissionCheckConfigDict(
setting_group=self.hamletcharacters_group,
users_without_permission=[self.moderator],
users_with_permission=[hamlet],
),
# Check case when can_administer_channel_group is set to an anonymous group.
PermissionCheckConfigDict(
setting_group=anonymous_group_dict,
users_without_permission=[self.moderator, hamlet],
users_with_permission=[prospero],
),
]
for check_config in group_permission_checks:
do_change_stream_group_based_setting(
stream,
"can_administer_channel_group",
check_config["setting_group"],
acting_user=self.admin,
)
for user in check_config["users_without_permission"]:
error_msg = default_error_msg
if stream.invite_only and not subscribed_to_stream(user, stream.id):
# In private streams, users that are not subscribed cannot access
# the stream.
error_msg = "Invalid channel ID"
check_channel_property_update(user, allow_fail=True, error_msg=error_msg)
for user in check_config["users_with_permission"]:
check_channel_property_update(user)
# Check guests cannot update property even when they belong
# to "can_administer_channel_group".
check_channel_property_update(self.guest, allow_fail=True, error_msg="Invalid channel ID")
self.subscribe(self.guest, stream.name)
check_channel_property_update(self.guest, allow_fail=True)
self.unsubscribe(self.guest, stream.name)
def test_administering_permission_for_updating_channel(self) -> None:
"""
This test is only for checking permission to update basic channel
properties like name, description, folder and permission to unarchive
the channel. Other things like permission to update group settings and
channel privacy are tested separately.
"""
public_stream = self.make_stream("test stream")
private_stream = self.make_stream("private_stream", invite_only=True)
self.subscribe(self.admin, private_stream.name)
self.subscribe(self.moderator, private_stream.name)
self.subscribe(self.example_user("hamlet"), private_stream.name)
self.subscribe(self.example_user("prospero"), private_stream.name)
unsubscribed_private_stream = self.make_stream(
"unsubscribed_private_stream", invite_only=True
)
# Subscribing a user that is not used in this test, as we do not allow
# unarchiving vacant private streams.
self.subscribe(self.example_user("desdemona"), unsubscribed_private_stream.name)
channel_folder = check_add_channel_folder(
self.realm, "Frontend", "", acting_user=self.admin
)
for stream in [public_stream, private_stream, unsubscribed_private_stream]:
self.do_test_updating_channel(stream, "name", "Renamed stream")
self.do_test_updating_channel(stream, "description", "Edited stream description")
self.do_test_updating_channel(stream, "folder_id", channel_folder.id)
do_deactivate_stream(stream, acting_user=None)
self.do_test_updating_channel(stream, "deactivated", False)
def check_channel_privacy_update(
self, user: UserProfile, property_name: str, new_value: bool, error_msg: str | None = None
) -> None:
stream = get_stream("test_stream", user.realm)
data = {}
if property_name == "invite_only":
data["is_private"] = orjson.dumps(new_value).decode()
else:
data[property_name] = orjson.dumps(new_value).decode()
old_value = getattr(stream, property_name)
result = self.api_patch(user, f"/api/v1/streams/{stream.id}", info=data)
if error_msg is not None:
self.assert_json_error(result, error_msg)
return
self.assert_json_success(result)
stream.refresh_from_db()
self.assertEqual(getattr(stream, property_name), new_value)
# Reset to original value.
setattr(stream, property_name, old_value)
stream.save(update_fields=[property_name])
# Reset history_public_to_subscribers field when stream
# is changed from private to public.
if not stream.invite_only and not stream.history_public_to_subscribers:
stream.history_public_to_subscribers = True
stream.save(update_fields=["history_public_to_subscribers"])
def do_test_updating_channel_privacy(self, property_name: str, new_value: bool) -> None:
hamlet = self.example_user("hamlet")
prospero = self.example_user("prospero")
stream = get_stream("test_stream", self.realm)
data = {}
if property_name == "invite_only":
data["is_private"] = orjson.dumps(new_value).decode()
else:
data[property_name] = orjson.dumps(new_value).decode()
default_error_msg = "You do not have permission to administer this channel."
anonymous_group_dict = UserGroupMembersData(
direct_members=[prospero.id, self.guest.id], direct_subgroups=[]
)
group_permission_checks: list[PermissionCheckConfigDict] = [
# Check admin can always administer channel.
PermissionCheckConfigDict(
setting_group=self.nobody_group,
users_without_permission=[self.moderator],
users_with_permission=[self.admin],
),
# Check case when can_administer_channel_group is set to a system group.
PermissionCheckConfigDict(
setting_group=self.moderators_group,
users_without_permission=[hamlet],
users_with_permission=[self.moderator],
),
# Check case when can_administer_channel_group is set to a user-defined group.
PermissionCheckConfigDict(
setting_group=self.hamletcharacters_group,
users_without_permission=[self.moderator],
users_with_permission=[hamlet],
),
# Check case when can_administer_channel_group is set to an anonymous group.
PermissionCheckConfigDict(
setting_group=anonymous_group_dict,
users_without_permission=[self.moderator, hamlet],
users_with_permission=[prospero],
),
]
for check_config in group_permission_checks:
do_change_stream_group_based_setting(
stream,
"can_administer_channel_group",
check_config["setting_group"],
acting_user=self.admin,
)
for user in check_config["users_without_permission"]:
self.check_channel_privacy_update(user, property_name, new_value, default_error_msg)
for user in check_config["users_with_permission"]:
self.check_channel_privacy_update(user, property_name, new_value)
# Check guests cannot update property even when they belong
# to "can_administer_channel_group".
self.check_channel_privacy_update(
self.guest, property_name, new_value, error_msg="Invalid channel ID"
)
self.subscribe(self.guest, stream.name)
self.check_channel_privacy_update(self.guest, property_name, new_value, default_error_msg)
self.unsubscribe(self.guest, stream.name)
def test_administering_permission_for_updating_channel_privacy(self) -> None:
stream = self.make_stream("test_stream")
# Give permission to create web-public channels to everyone, so
# that we can check administering permissions easily, although
# we do not do not allow members to create web-public channels
# in production.
do_change_realm_permission_group_setting(
self.realm, "can_create_web_public_channel_group", self.members_group, acting_user=None
)
# Test making a public stream private with protected history.
self.do_test_updating_channel_privacy("invite_only", True)
# Test making a public stream web-public.
self.do_test_updating_channel_privacy("is_web_public", True)
do_change_stream_permission(
stream,
invite_only=True,
history_public_to_subscribers=False,
is_web_public=False,
acting_user=self.admin,
)
self.subscribe(self.admin, stream.name)
self.subscribe(self.moderator, stream.name)
self.subscribe(self.example_user("hamlet"), stream.name)
self.subscribe(self.example_user("prospero"), stream.name)
# Test making a private stream with protected history public.
self.do_test_updating_channel_privacy("invite_only", False)
def test_permission_for_updating_privacy_of_unsubscribed_private_channel(self) -> None:
hamlet = self.example_user("hamlet")
stream = self.make_stream("test_stream", invite_only=True)
do_change_stream_group_based_setting(
stream, "can_administer_channel_group", self.members_group, acting_user=self.admin
)
error_msg = "Channel content access is required."
self.check_channel_privacy_update(self.admin, "invite_only", False, error_msg)
self.check_channel_privacy_update(self.moderator, "invite_only", False, error_msg)
self.check_channel_privacy_update(hamlet, "invite_only", False, error_msg)
do_change_stream_group_based_setting(
stream, "can_add_subscribers_group", self.moderators_group, acting_user=self.admin
)
self.check_channel_privacy_update(hamlet, "invite_only", False, error_msg=error_msg)
self.check_channel_privacy_update(self.admin, "invite_only", False)
self.check_channel_privacy_update(self.moderator, "invite_only", False)
# Users who are part of can_subscribe_group get content access
# to a private stream even if they are not subscribed to it.
do_change_stream_group_based_setting(
stream, "can_subscribe_group", self.hamletcharacters_group, acting_user=self.admin
)
self.check_channel_privacy_update(hamlet, "invite_only", False)
def check_channel_group_setting_update(
self, user: UserProfile, property_name: str, error_msg: str | None = None
) -> None:
stream = get_stream("test_stream", user.realm)
new_value = self.hamletcharacters_group.id
data = {}
data[property_name] = orjson.dumps({"new": new_value}).decode()
old_value = getattr(stream, property_name)
# old_value is stored as UserGroupMembersData dict if the
# setting is set to an anonymous group and a NamedUserGroup
# object otherwise, so that we can pass it directly to
# do_change_stream_group_based_setting.
if not hasattr(old_value, "named_user_group"):
old_value = get_group_setting_value_for_api(old_value)
else:
old_value = old_value.named_user_group
result = self.api_patch(user, f"/api/v1/streams/{stream.id}", info=data)
if error_msg is not None:
self.assert_json_error(result, error_msg)
return
self.assert_json_success(result)
stream.refresh_from_db()
self.assertEqual(getattr(stream, property_name + "_id"), new_value)
# Reset to original value.
do_change_stream_group_based_setting(
stream, property_name, old_value, acting_user=self.example_user("iago")
)
def do_test_updating_channel_group_settings(self, property_name: str) -> None:
hamlet = self.example_user("hamlet")
prospero = self.example_user("prospero")
stream = get_stream("test_stream", self.realm)
default_error_msg = "You do not have permission to administer this channel."
anonymous_group_dict = UserGroupMembersData(
direct_members=[prospero.id, self.guest.id], direct_subgroups=[]
)
group_permission_checks: list[PermissionCheckConfigDict] = [
# Check admin can always administer channel.
PermissionCheckConfigDict(
setting_group=self.nobody_group,
users_without_permission=[self.moderator],
users_with_permission=[self.admin],
),
# Check case when can_administer_channel_group is set to a system group.
PermissionCheckConfigDict(
setting_group=self.moderators_group,
users_without_permission=[hamlet],
users_with_permission=[self.moderator],
),
# Check case when can_administer_channel_group is set to a user-defined group.
PermissionCheckConfigDict(
setting_group=self.hamletcharacters_group,
users_without_permission=[self.moderator],
users_with_permission=[hamlet],
),
# Check case when can_administer_channel_group is set to an anonymous group.
PermissionCheckConfigDict(
setting_group=anonymous_group_dict,
users_without_permission=[self.moderator, hamlet],
users_with_permission=[prospero],
),
]
for check_config in group_permission_checks:
do_change_stream_group_based_setting(
stream,
"can_administer_channel_group",
check_config["setting_group"],
acting_user=self.admin,
)
for user in check_config["users_without_permission"]:
self.check_channel_group_setting_update(user, property_name, default_error_msg)
for user in check_config["users_with_permission"]:
self.check_channel_group_setting_update(user, property_name)
# Check guests cannot update property even when they belong
# to "can_administer_channel_group".
self.check_channel_group_setting_update(
self.guest, property_name, error_msg="Invalid channel ID"
)
self.subscribe(self.guest, stream.name)
self.check_channel_group_setting_update(self.guest, property_name, default_error_msg)
self.unsubscribe(self.guest, stream.name)
def do_test_updating_group_settings_for_unsubscribed_private_channels(
self, property_name: str
) -> None:
# If stream is private, test which permissions require having
# content access to the channel.
hamlet = self.example_user("hamlet")
stream = get_stream("test_stream", self.realm)
self.assertTrue(stream.invite_only)
do_change_stream_group_based_setting(
stream, "can_administer_channel_group", self.members_group, acting_user=self.admin
)
if property_name not in Stream.stream_permission_group_settings_requiring_content_access:
# Users without content access can modify properties not in
# stream_permission_group_settings_requiring_content_access.
self.check_channel_group_setting_update(self.admin, property_name)
self.check_channel_group_setting_update(self.moderator, property_name)
self.check_channel_group_setting_update(hamlet, property_name)
return
error_msg = "Channel content access is required."
# Even realm and channel admins need content access to
# a private channel to update the permissions in
# stream_permission_group_settings_requiring_content_access.
self.check_channel_group_setting_update(self.admin, property_name, error_msg=error_msg)
self.check_channel_group_setting_update(self.moderator, property_name, error_msg=error_msg)
self.check_channel_group_setting_update(hamlet, property_name, error_msg=error_msg)
# Users who are part of can_add_subscribers_group get content access
# to a private stream even if they are not subscribed to it.
do_change_stream_group_based_setting(
stream, "can_add_subscribers_group", self.moderators_group, acting_user=self.admin
)
self.check_channel_group_setting_update(hamlet, property_name, error_msg=error_msg)
self.check_channel_group_setting_update(self.admin, property_name)
self.check_channel_group_setting_update(self.moderator, property_name)
# Users who are part of can_subscribe_group get content access
# to a private stream even if they are not subscribed to it.
do_change_stream_group_based_setting(
stream, "can_subscribe_group", self.hamletcharacters_group, acting_user=self.admin
)
self.check_channel_group_setting_update(hamlet, property_name)
# Reset the setting values to "Nobody" group.
do_change_stream_group_based_setting(
stream, "can_add_subscribers_group", self.nobody_group, acting_user=self.admin
)
do_change_stream_group_based_setting(
stream, "can_subscribe_group", self.nobody_group, acting_user=self.admin
)
def test_administering_permission_for_updating_channel_group_settings(self) -> None:
stream = self.make_stream("test_stream")
hamlet = self.example_user("hamlet")
prospero = self.example_user("prospero")
for setting_name in Stream.stream_permission_group_settings:
self.do_test_updating_channel_group_settings(setting_name)
# Test changing group settings for a private stream when user is
# subscribed to the stream.
do_change_stream_permission(
stream,
invite_only=True,
history_public_to_subscribers=False,
is_web_public=False,
acting_user=self.admin,
)
for user in [self.admin, self.moderator, hamlet, prospero]:
self.subscribe(user, stream.name)
for setting_name in Stream.stream_permission_group_settings:
self.do_test_updating_channel_group_settings(setting_name)
# Unsubscribe user from private stream to test gaining
# content access from group settings.
for user in [self.admin, self.moderator, hamlet, prospero]:
self.unsubscribe(user, stream.name)
for setting_name in Stream.stream_permission_group_settings:
self.do_test_updating_group_settings_for_unsubscribed_private_channels(setting_name)

View File

@@ -293,29 +293,6 @@ class StreamAdminTest(ZulipTestCase):
self.assert_json_error(result, "Moderation request channel must be private.")
self.assertTrue(private_stream.invite_only)
do_change_user_role(user_profile, UserProfile.ROLE_MEMBER, acting_user=None)
params = {
"is_private": orjson.dumps(False).decode(),
}
stream = self.subscribe(user_profile, "private_stream_2")
self.assertFalse(is_user_in_group(stream.can_administer_channel_group_id, user_profile))
result = self.client_patch(f"/json/streams/{stream.id}", params)
self.assertTrue(stream.invite_only)
self.assert_json_error(result, "You do not have permission to administer this channel.")
user_profile_group = check_add_user_group(
realm, "user_profile_group", [user_profile], acting_user=user_profile
)
do_change_stream_group_based_setting(
stream,
"can_administer_channel_group",
user_profile_group,
acting_user=user_profile,
)
result = self.client_patch(f"/json/streams/{stream.id}", params)
self.assertTrue(stream.invite_only)
self.assert_json_success(result)
stream = self.subscribe(user_profile, "private_stream_3", invite_only=True)
do_change_user_role(user_profile, UserProfile.ROLE_REALM_OWNER, acting_user=None)
nobody_group = NamedUserGroup.objects.get(
@@ -330,6 +307,9 @@ class StreamAdminTest(ZulipTestCase):
result = self.client_patch(f"/json/streams/{stream.id}", params)
self.assert_json_error(result, "Insufficient permission")
user_profile_group = check_add_user_group(
realm, "user_profile_group", [user_profile], acting_user=user_profile
)
do_change_realm_permission_group_setting(
realm,
"can_create_public_channel_group",
@@ -402,29 +382,6 @@ class StreamAdminTest(ZulipTestCase):
self.assert_json_error(result, "A default channel cannot be private.")
self.assertFalse(default_stream.invite_only)
do_change_user_role(user_profile, UserProfile.ROLE_MEMBER, acting_user=None)
params = {
"is_private": orjson.dumps(True).decode(),
}
stream = self.subscribe(user_profile, "public_stream_2")
self.assertFalse(is_user_in_group(stream.can_administer_channel_group_id, user_profile))
result = self.client_patch(f"/json/streams/{stream.id}", params)
self.assertFalse(stream.invite_only)
self.assert_json_error(result, "You do not have permission to administer this channel.")
user_profile_group = check_add_user_group(
realm, "user_profile_group", [user_profile], acting_user=user_profile
)
do_change_stream_group_based_setting(
stream,
"can_administer_channel_group",
user_profile_group,
acting_user=user_profile,
)
result = self.client_patch(f"/json/streams/{stream.id}", params)
self.assertFalse(stream.invite_only)
self.assert_json_success(result)
stream = self.subscribe(user_profile, "public_stream_3")
do_change_user_role(user_profile, UserProfile.ROLE_REALM_OWNER, acting_user=None)
nobody_group = NamedUserGroup.objects.get(
@@ -439,6 +396,9 @@ class StreamAdminTest(ZulipTestCase):
result = self.client_patch(f"/json/streams/{stream.id}", params)
self.assert_json_error(result, "Insufficient permission")
user_profile_group = check_add_user_group(
realm, "user_profile_group", [user_profile], acting_user=user_profile
)
do_change_realm_permission_group_setting(
realm,
"can_create_private_channel_group",
@@ -624,14 +584,20 @@ class StreamAdminTest(ZulipTestCase):
stream = self.subscribe(user_profile, "test_stream")
stream_id = stream.id
user_profile_group = check_add_user_group(
realm, "user_profile_group", [user_profile], acting_user=user_profile
)
do_change_stream_group_based_setting(
stream,
"can_administer_channel_group",
user_profile_group,
acting_user=user_profile,
)
params = {
"is_web_public": orjson.dumps(True).decode(),
"history_public_to_subscribers": orjson.dumps(True).decode(),
}
self.assertFalse(is_user_in_group(stream.can_administer_channel_group_id, user_profile))
result = self.client_patch(f"/json/streams/{stream_id}", params)
self.assert_json_error(result, "You do not have permission to administer this channel.")
owners_group = NamedUserGroup.objects.get(
name=SystemGroups.OWNERS, realm=realm, is_system_group=True
)
@@ -716,37 +682,6 @@ class StreamAdminTest(ZulipTestCase):
}
self.assertEqual(realm_audit_log.extra_data, expected_extra_data)
# Test non-admin belonging to can_administer_channel_group
# can also make the stream public.
do_change_user_role(user_profile, UserProfile.ROLE_MEMBER, acting_user=None)
stream = self.make_stream("test_stream_1", realm=realm)
stream_id = self.subscribe(user_profile, "test_stream_1").id
user_profile_group = check_add_user_group(
realm, "user_profile_group", [user_profile], acting_user=user_profile
)
do_change_realm_permission_group_setting(
realm,
"can_create_web_public_channel_group",
user_profile_group,
acting_user=None,
)
params = {
"is_web_public": orjson.dumps(True).decode(),
"history_public_to_subscribers": orjson.dumps(True).decode(),
}
self.assertFalse(is_user_in_group(stream.can_administer_channel_group_id, user_profile))
result = self.client_patch(f"/json/streams/{stream_id}", params)
self.assert_json_error(result, "You do not have permission to administer this channel.")
do_change_stream_group_based_setting(
stream,
"can_administer_channel_group",
user_profile_group,
acting_user=user_profile,
)
result = self.client_patch(f"/json/streams/{stream_id}", params)
self.assert_json_success(result)
def test_change_history_access_for_private_streams(self) -> None:
user_profile = self.example_user("iago")
self.login_user(user_profile)
@@ -1411,52 +1346,6 @@ class StreamAdminTest(ZulipTestCase):
},
)
def test_permissions_and_archiving_behavior(self) -> None:
"""
Test permissions for archiving and unarchiving streams, and ensure users without
the necessary permissions cannot archive or unarchive a stream.
"""
desdemona = self.example_user("desdemona")
iago = self.example_user("iago")
stream = self.make_stream("test_stream", invite_only=False)
self.subscribe(iago, stream.name)
do_deactivate_stream(stream, acting_user=None)
stream.refresh_from_db()
self.assertTrue(stream.deactivated)
data = {}
data["is_archived"] = "false"
result = self.api_patch(desdemona, f"/api/v1/streams/{stream.id}", info=data)
self.assert_json_success(result)
stream.refresh_from_db()
self.assertFalse(stream.deactivated)
cordelia = self.example_user("cordelia")
stream1 = self.make_stream("test_stream_1", invite_only=False)
self.subscribe(iago, stream1.name)
do_deactivate_stream(stream1, acting_user=None)
stream1.refresh_from_db()
self.assertTrue(stream1.deactivated)
result = self.api_patch(cordelia, f"/api/v1/streams/{stream1.id}", info=data)
self.assert_json_error(result, "You do not have permission to administer this channel.")
do_change_stream_group_based_setting(
stream1,
"can_administer_channel_group",
UserGroupMembersData(direct_members=[cordelia.id], direct_subgroups=[]),
acting_user=desdemona,
)
result = self.api_patch(cordelia, f"/api/v1/streams/{stream1.id}", info=data)
self.assert_json_success(result)
stream1.refresh_from_db()
self.assertFalse(stream1.deactivated)
def test_is_archived_true_does_not_archive_stream(self) -> None:
"""
Ensure that passing `is_archived` as True does not archive the stream.
@@ -1543,20 +1432,10 @@ class StreamAdminTest(ZulipTestCase):
realm = user_profile.realm
stream = self.subscribe(user_profile, "stream_name")
user_profile_group = check_add_user_group(
realm, "user_profile_group", [user_profile], acting_user=user_profile
)
do_change_stream_group_based_setting(
stream,
"can_administer_channel_group",
user_profile_group,
acting_user=user_profile,
)
do_change_user_role(user_profile, UserProfile.ROLE_REALM_ADMINISTRATOR, acting_user=None)
result = self.client_patch(f"/json/streams/{stream.id}", {"new_name": "stream_name1"})
self.assert_json_success(result)
do_change_user_role(user_profile, UserProfile.ROLE_REALM_ADMINISTRATOR, acting_user=None)
result = self.client_patch(f"/json/streams/{stream.id}", {"new_name": "stream_name1"})
self.assert_json_error(result, "Channel already has that name.")
result = self.client_patch(f"/json/streams/{stream.id}", {"new_name": "Denmark"})
@@ -1735,17 +1614,6 @@ class StreamAdminTest(ZulipTestCase):
# User belonging to `can_subscribe_group` should be notified.
self.assertIn(self.example_user("ZOE").id, notified_user_ids)
def test_rename_stream_requires_admin(self) -> None:
user_profile = self.example_user("hamlet")
self.login_user(user_profile)
stream = self.make_stream("stream_name1")
self.subscribe(user_profile, "stream_name1")
stream_id = get_stream("stream_name1", user_profile.realm).id
self.assertFalse(is_user_in_group(stream.can_administer_channel_group_id, user_profile))
result = self.client_patch(f"/json/streams/{stream_id}", {"new_name": "stream_name2"})
self.assert_json_error(result, "You do not have permission to administer this channel.")
def test_notify_on_stream_rename(self) -> None:
user_profile = self.example_user("hamlet")
self.login_user(user_profile)
@@ -2015,21 +1883,6 @@ class StreamAdminTest(ZulipTestCase):
f'<p><a class="stream-topic" data-stream-id="{core_stream.id}" href="/#narrow/channel/{core_stream.id}-core/topic/testing/with/{msg_id}">#{core_stream.name} &gt; testing</a></p>',
)
def test_change_stream_description_requires_administer_channel_permissions(self) -> None:
user_profile = self.example_user("hamlet")
self.login_user(user_profile)
self.make_stream("stream_name1")
self.subscribe(user_profile, "stream_name1")
do_change_user_role(user_profile, UserProfile.ROLE_MEMBER, acting_user=None)
stream = get_stream("stream_name1", user_profile.realm)
self.assertFalse(is_user_in_group(stream.can_administer_channel_group_id, user_profile))
result = self.client_patch(
f"/json/streams/{stream.id}", {"description": "Test description"}
)
self.assert_json_error(result, "You do not have permission to administer this channel.")
def test_change_stream_message_retention_days_notifications(self) -> None:
user_profile = self.example_user("desdemona")
self.login_user(user_profile)
@@ -2213,43 +2066,10 @@ class StreamAdminTest(ZulipTestCase):
nobody_group = NamedUserGroup.objects.get(
name="role:nobody", is_system_group=True, realm=realm
)
do_change_stream_group_based_setting(
stream,
"can_administer_channel_group",
nobody_group,
acting_user=user_profile,
)
moderators_system_group = NamedUserGroup.objects.get(
name="role:moderators", realm=realm, is_system_group=True
)
shiva = self.example_user("shiva")
self.login_user(shiva)
self.assertFalse(is_user_in_group(stream.can_administer_channel_group_id, shiva))
params = {}
params[setting_name] = orjson.dumps({"new": moderators_system_group.id}).decode()
result = self.client_patch(f"/json/streams/{stream.id}", params)
self.assert_json_error(result, "You do not have permission to administer this channel.")
do_change_stream_group_based_setting(
stream,
"can_administer_channel_group",
moderators_system_group,
acting_user=user_profile,
)
members_system_group = NamedUserGroup.objects.get(
name="role:members", realm=realm, is_system_group=True
)
params[setting_name] = orjson.dumps({"new": members_system_group.id}).decode()
result = self.client_patch(
f"/json/streams/{stream.id}",
params,
)
self.assert_json_success(result)
stream = get_stream("stream_name1", realm)
self.assertEqual(getattr(stream, setting_name).id, members_system_group.id)
self.login("iago")
params[setting_name] = orjson.dumps({"new": moderators_system_group.id}).decode()
@@ -2360,90 +2180,8 @@ class StreamAdminTest(ZulipTestCase):
f"'{setting_name}' setting cannot be set to 'role:internet' group.",
)
# For private streams, realm admins need not be subscribed to
# the stream to change the setting as they can administer the
# channel by default.
stream = get_stream("stream_name2", realm)
params[setting_name] = orjson.dumps({"new": moderators_system_group.id}).decode()
result = self.client_patch(
f"/json/streams/{stream.id}",
params,
)
if setting_name in Stream.stream_permission_group_settings_requiring_content_access:
self.assert_json_error(result, "Channel content access is required.")
else:
self.assert_json_success(result)
stream = get_stream("stream_name2", realm)
self.assertEqual(getattr(stream, setting_name).id, moderators_system_group.id)
# For private streams, channel admins need not be subscribed to
# the stream to change the setting as they can administer the
# channel by default.
shiva_group_member_dict = UserGroupMembersData(
direct_members=[shiva.id], direct_subgroups=[]
)
do_change_stream_group_based_setting(
stream,
"can_administer_channel_group",
shiva_group_member_dict,
acting_user=shiva,
)
self.assertTrue(is_user_in_group(stream.can_administer_channel_group_id, shiva))
params[setting_name] = orjson.dumps({"new": owners_group.id}).decode()
self.login_user(shiva)
result = self.client_patch(
f"/json/streams/{stream.id}",
params,
)
if setting_name in Stream.stream_permission_group_settings_requiring_content_access:
self.assert_json_error(result, "Channel content access is required.")
do_change_stream_group_based_setting(
stream,
"can_add_subscribers_group",
shiva_group_member_dict,
acting_user=shiva,
)
result = self.client_patch(
f"/json/streams/{stream.id}",
params,
)
self.assert_json_success(result)
stream = get_stream("stream_name2", realm)
self.assertEqual(getattr(stream, setting_name).id, owners_group.id)
else:
self.assert_json_success(result)
stream = get_stream("stream_name2", realm)
self.assertEqual(getattr(stream, setting_name).id, owners_group.id)
# Guest user cannot be a channel admin for a public channel.
# `user_has_permission_for_group_setting` will not allow a guest
# to be a part of `can_administer_channel_group` since that
# group has `allow_everyone_group` set to false.
stream = get_stream("stream_name1", realm)
polonius = self.example_user("polonius")
polonius_group_member_dict = UserGroupMembersData(
direct_members=[polonius.id], direct_subgroups=[]
)
do_change_stream_group_based_setting(
stream,
"can_administer_channel_group",
polonius_group_member_dict,
acting_user=polonius,
)
subbed_users = self.users_subscribed_to_stream(stream.name, polonius.realm)
self.assertNotIn(polonius, subbed_users)
self.login_user(polonius)
result = self.client_patch(
f"/json/streams/{stream.id}",
params,
)
self.assert_json_error(result, "Invalid channel ID")
def test_changing_stream_permission_settings(self) -> None:
self.make_stream("stream_name1")
self.make_stream("stream_name2", invite_only=True)
# Subscribe at least one user to the private stream.
self.subscribe(self.example_user("hamlet"), "stream_name2")
for setting_name in Stream.stream_permission_group_settings:
self.do_test_change_stream_permission_setting(setting_name)
@@ -2916,56 +2654,6 @@ class StreamAdminTest(ZulipTestCase):
)
self.assert_json_error(result, "Invalid channel folder ID")
def test_permission_to_change_stream_folder(self) -> None:
iago = self.example_user("iago")
hamlet = self.example_user("hamlet")
realm = iago.realm
channel_folder = check_add_channel_folder(realm, "Frontend", "", acting_user=iago)
stream = self.make_stream("test_stream")
self.assertIsNone(stream.folder_id)
nobody_group = NamedUserGroup.objects.get(
name=SystemGroups.NOBODY, realm=realm, is_system_group=True
)
do_change_stream_group_based_setting(
stream,
"can_administer_channel_group",
nobody_group,
acting_user=iago,
)
result = self.api_patch(
iago,
f"/api/v1/streams/{stream.id}",
{"folder_id": orjson.dumps(channel_folder.id).decode()},
)
self.assert_json_success(result)
stream = get_stream("test_stream", realm)
self.assertEqual(stream.folder_id, channel_folder.id)
result = self.api_patch(
hamlet,
f"/api/v1/streams/{stream.id}",
{"folder_id": orjson.dumps(None).decode()},
)
self.assert_json_error(result, "You do not have permission to administer this channel.")
do_change_stream_group_based_setting(
stream,
"can_administer_channel_group",
UserGroupMembersData(direct_members=[hamlet.id], direct_subgroups=[]),
acting_user=iago,
)
result = self.api_patch(
hamlet,
f"/api/v1/streams/{stream.id}",
{"folder_id": orjson.dumps(None).decode()},
)
self.assert_json_success(result)
stream = get_stream("test_stream", realm)
self.assertIsNone(stream.folder_id)
def attempt_unsubscribe_of_principal(
self,
target_users: list[UserProfile],