streams: Refactor code to handle group setting values.

This commit updates the code which computes the dict for
setting groups mapping named user groups to ID and anonymous
groups to UserGroupMembersDict. After the changes, the dict
contains only anonymous groups values and the setting values
for group IDs not present in dict will be computed based on
the fact that those are named user groups.

This is a preparatory refactor for optimizing computing group
setting values for register response by fetching all anonymous
groups membership data just once.
This commit is contained in:
Sahil Batra
2025-03-13 21:13:17 +05:30
committed by Tim Abbott
parent 512613ead4
commit bc2afd45b3
5 changed files with 141 additions and 109 deletions

View File

@@ -38,7 +38,7 @@ from zerver.lib.stream_traffic import get_streams_traffic
from zerver.lib.streams import ( from zerver.lib.streams import (
can_access_stream_metadata_user_ids, can_access_stream_metadata_user_ids,
check_basic_stream_access, check_basic_stream_access,
get_group_setting_value_dict_for_streams, get_anonymous_group_membership_dict_for_streams,
get_stream_permission_policy_name, get_stream_permission_policy_name,
get_stream_post_policy_value_based_on_group_setting, get_stream_post_policy_value_based_on_group_setting,
get_user_ids_with_metadata_access_via_permission_groups, get_user_ids_with_metadata_access_via_permission_groups,
@@ -270,8 +270,10 @@ def do_unarchive_stream(stream: Stream, new_name: str, *, acting_user: UserProfi
recent_traffic = get_streams_traffic({stream.id}, realm) recent_traffic = get_streams_traffic({stream.id}, realm)
notify_user_ids = list(can_access_stream_metadata_user_ids(stream)) notify_user_ids = list(can_access_stream_metadata_user_ids(stream))
setting_groups_dict = get_group_setting_value_dict_for_streams([stream]) anonymous_group_membership = get_anonymous_group_membership_dict_for_streams([stream])
send_stream_creation_event(realm, stream, notify_user_ids, recent_traffic, setting_groups_dict) send_stream_creation_event(
realm, stream, notify_user_ids, recent_traffic, anonymous_group_membership
)
sender = get_system_bot(settings.NOTIFICATION_BOT, stream.realm_id) sender = get_system_bot(settings.NOTIFICATION_BOT, stream.realm_id)
with override_language(stream.realm.default_language): with override_language(stream.realm.default_language):
@@ -392,7 +394,7 @@ def send_subscription_add_events(
stream_subscribers_dict[stream.id] = subscribers stream_subscribers_dict[stream.id] = subscribers
streams = [sub_info.stream for sub_info in sub_info_list] streams = [sub_info.stream for sub_info in sub_info_list]
setting_groups_dict = get_group_setting_value_dict_for_streams(streams) anonymous_group_membership = get_anonymous_group_membership_dict_for_streams(streams)
for user_id, sub_infos in info_by_user.items(): for user_id, sub_infos in info_by_user.items():
sub_dicts: list[APISubscriptionDict] = [] sub_dicts: list[APISubscriptionDict] = []
@@ -400,7 +402,7 @@ def send_subscription_add_events(
stream = sub_info.stream stream = sub_info.stream
stream_subscribers = stream_subscribers_dict[stream.id] stream_subscribers = stream_subscribers_dict[stream.id]
subscription = sub_info.sub subscription = sub_info.sub
stream_dict = stream_to_dict(stream, recent_traffic, setting_groups_dict) stream_dict = stream_to_dict(stream, recent_traffic, anonymous_group_membership)
# This is verbose as we cannot unpack existing TypedDict # This is verbose as we cannot unpack existing TypedDict
# to initialize another TypedDict while making mypy happy. # to initialize another TypedDict while making mypy happy.
# https://github.com/python/mypy/issues/5382 # https://github.com/python/mypy/issues/5382
@@ -499,7 +501,7 @@ def send_stream_creation_events_for_previously_inaccessible_streams(
recent_traffic = get_streams_traffic(stream_ids, realm) recent_traffic = get_streams_traffic(stream_ids, realm)
streams = [stream_dict[stream_id] for stream_id in stream_ids] streams = [stream_dict[stream_id] for stream_id in stream_ids]
setting_groups_dict: dict[int, int | UserGroupMembersDict] | None = None anonymous_group_membership: dict[int, UserGroupMembersDict] | None = None
for stream_id, stream_users_ids in altered_user_dict.items(): for stream_id, stream_users_ids in altered_user_dict.items():
stream = stream_dict[stream_id] stream = stream_dict[stream_id]
@@ -526,11 +528,13 @@ def send_stream_creation_events_for_previously_inaccessible_streams(
notify_user_ids = list(stream_users_ids & altered_guests) notify_user_ids = list(stream_users_ids & altered_guests)
if notify_user_ids: if notify_user_ids:
if setting_groups_dict is None: if anonymous_group_membership is None:
setting_groups_dict = get_group_setting_value_dict_for_streams(streams) anonymous_group_membership = get_anonymous_group_membership_dict_for_streams(
streams
)
send_stream_creation_event( send_stream_creation_event(
realm, stream, notify_user_ids, recent_traffic, setting_groups_dict realm, stream, notify_user_ids, recent_traffic, anonymous_group_membership
) )
@@ -1289,9 +1293,13 @@ def do_change_stream_permission(
) )
recent_traffic = get_streams_traffic({stream.id}, realm) recent_traffic = get_streams_traffic({stream.id}, realm)
setting_groups_dict = get_group_setting_value_dict_for_streams([stream]) anonymous_group_membership = get_anonymous_group_membership_dict_for_streams([stream])
send_stream_creation_event( send_stream_creation_event(
realm, stream, list(notify_stream_creation_ids), recent_traffic, setting_groups_dict realm,
stream,
list(notify_stream_creation_ids),
recent_traffic,
anonymous_group_membership,
) )
# Add subscribers info to the stream object. We need to send peer_add # Add subscribers info to the stream object. We need to send peer_add
@@ -1687,13 +1695,13 @@ def do_change_stream_group_based_setting(
if len(user_ids_gaining_metadata_access) > 0: if len(user_ids_gaining_metadata_access) > 0:
recent_traffic = get_streams_traffic({stream.id}, stream.realm) recent_traffic = get_streams_traffic({stream.id}, stream.realm)
setting_groups_dict = get_group_setting_value_dict_for_streams([stream]) anonymous_group_membership = get_anonymous_group_membership_dict_for_streams([stream])
send_stream_creation_event( send_stream_creation_event(
stream.realm, stream.realm,
stream, stream,
list(user_ids_gaining_metadata_access), list(user_ids_gaining_metadata_access),
recent_traffic, recent_traffic,
setting_groups_dict, anonymous_group_membership,
) )
if len(user_ids_losing_metadata_access) > 0: if len(user_ids_losing_metadata_access) > 0:
send_stream_deletion_event(stream.realm, user_ids_losing_metadata_access, [stream]) send_stream_deletion_event(stream.realm, user_ids_losing_metadata_access, [stream])

View File

@@ -33,7 +33,7 @@ from zerver.lib.sessions import delete_user_sessions
from zerver.lib.soft_deactivation import queue_soft_reactivation from zerver.lib.soft_deactivation import queue_soft_reactivation
from zerver.lib.stream_traffic import get_streams_traffic from zerver.lib.stream_traffic import get_streams_traffic
from zerver.lib.streams import ( from zerver.lib.streams import (
get_group_setting_value_dict_for_streams, get_anonymous_group_membership_dict_for_streams,
get_streams_for_user, get_streams_for_user,
send_stream_deletion_event, send_stream_deletion_event,
stream_to_dict, stream_to_dict,
@@ -566,13 +566,15 @@ def send_stream_events_for_role_update(
if stream.id in now_accessible_stream_ids if stream.id in now_accessible_stream_ids
] ]
setting_groups_dict = get_group_setting_value_dict_for_streams(now_accessible_streams) anonymous_group_membership = get_anonymous_group_membership_dict_for_streams(
now_accessible_streams
)
event = dict( event = dict(
type="stream", type="stream",
op="create", op="create",
streams=[ streams=[
stream_to_dict(stream, recent_traffic, setting_groups_dict) stream_to_dict(stream, recent_traffic, anonymous_group_membership)
for stream in now_accessible_streams for stream in now_accessible_streams
], ],
) )

View File

@@ -26,6 +26,7 @@ from zerver.lib.timestamp import datetime_to_timestamp
from zerver.lib.types import APIStreamDict, UserGroupMembersDict from zerver.lib.types import APIStreamDict, UserGroupMembersDict
from zerver.lib.user_groups import ( from zerver.lib.user_groups import (
UserGroupMembershipDetails, UserGroupMembershipDetails,
get_group_setting_value_for_register_api,
get_members_and_subgroups_of_groups, get_members_and_subgroups_of_groups,
get_recursive_membership_groups, get_recursive_membership_groups,
get_role_based_system_groups_dict, get_role_based_system_groups_dict,
@@ -145,12 +146,12 @@ def send_stream_creation_event(
stream: Stream, stream: Stream,
user_ids: list[int], user_ids: list[int],
recent_traffic: dict[int, int] | None = None, recent_traffic: dict[int, int] | None = None,
setting_groups_dict: dict[int, int | UserGroupMembersDict] | None = None, anonymous_group_membership: dict[int, UserGroupMembersDict] | None = None,
) -> None: ) -> None:
event = dict( event = dict(
type="stream", type="stream",
op="create", op="create",
streams=[stream_to_dict(stream, recent_traffic, setting_groups_dict)], streams=[stream_to_dict(stream, recent_traffic, anonymous_group_membership)],
) )
send_event_on_commit(realm, event, user_ids) send_event_on_commit(realm, event, user_ids)
@@ -262,7 +263,7 @@ def create_stream_if_needed(
can_remove_subscribers_group: UserGroup | None = None, can_remove_subscribers_group: UserGroup | None = None,
can_subscribe_group: UserGroup | None = None, can_subscribe_group: UserGroup | None = None,
acting_user: UserProfile | None = None, acting_user: UserProfile | None = None,
setting_groups_dict: dict[int, int | UserGroupMembersDict] | None = None, anonymous_group_membership: dict[int, UserGroupMembersDict] | None = None,
) -> tuple[Stream, bool]: ) -> tuple[Stream, bool]:
history_public_to_subscribers = get_default_value_for_history_public_to_subscribers( history_public_to_subscribers = get_default_value_for_history_public_to_subscribers(
realm, invite_only, history_public_to_subscribers realm, invite_only, history_public_to_subscribers
@@ -322,8 +323,8 @@ def create_stream_if_needed(
event_time=event_time, event_time=event_time,
) )
if setting_groups_dict is None: if anonymous_group_membership is None:
setting_groups_dict = get_group_setting_value_dict_for_streams([stream]) anonymous_group_membership = get_anonymous_group_membership_dict_for_streams([stream])
if stream.is_public(): if stream.is_public():
if stream.is_web_public: if stream.is_web_public:
@@ -334,7 +335,10 @@ def create_stream_if_needed(
# can_join_group. # can_join_group.
notify_user_ids = active_non_guest_user_ids(stream.realm_id) notify_user_ids = active_non_guest_user_ids(stream.realm_id)
send_stream_creation_event( send_stream_creation_event(
realm, stream, notify_user_ids, setting_groups_dict=setting_groups_dict realm,
stream,
notify_user_ids,
anonymous_group_membership=anonymous_group_membership,
) )
else: else:
realm_admin_ids = {user.id for user in stream.realm.get_admin_users_and_bots()} realm_admin_ids = {user.id for user in stream.realm.get_admin_users_and_bots()}
@@ -345,7 +349,7 @@ def create_stream_if_needed(
realm_admin_ids realm_admin_ids
| get_user_ids_with_metadata_access_via_permission_groups(stream) | get_user_ids_with_metadata_access_via_permission_groups(stream)
), ),
setting_groups_dict=setting_groups_dict, anonymous_group_membership=anonymous_group_membership,
) )
return stream, created return stream, created
@@ -355,7 +359,7 @@ def create_streams_if_needed(
realm: Realm, realm: Realm,
stream_dicts: list[StreamDict], stream_dicts: list[StreamDict],
acting_user: UserProfile | None = None, acting_user: UserProfile | None = None,
setting_groups_dict: dict[int, int | UserGroupMembersDict] | None = None, anonymous_group_membership: dict[int, UserGroupMembersDict] | None = None,
) -> tuple[list[Stream], list[Stream]]: ) -> tuple[list[Stream], list[Stream]]:
"""Note that stream_dict["name"] is assumed to already be stripped of """Note that stream_dict["name"] is assumed to already be stripped of
whitespace""" whitespace"""
@@ -377,7 +381,7 @@ def create_streams_if_needed(
can_remove_subscribers_group=stream_dict.get("can_remove_subscribers_group", None), can_remove_subscribers_group=stream_dict.get("can_remove_subscribers_group", None),
can_subscribe_group=stream_dict.get("can_subscribe_group", None), can_subscribe_group=stream_dict.get("can_subscribe_group", None),
acting_user=acting_user, acting_user=acting_user,
setting_groups_dict=setting_groups_dict, anonymous_group_membership=anonymous_group_membership,
) )
if created: if created:
@@ -1288,7 +1292,7 @@ def list_to_streams(
autocreate: bool = False, autocreate: bool = False,
unsubscribing_others: bool = False, unsubscribing_others: bool = False,
is_default_stream: bool = False, is_default_stream: bool = False,
setting_groups_dict: dict[int, int | UserGroupMembersDict] | None = None, anonymous_group_membership: dict[int, UserGroupMembersDict] | None = None,
) -> tuple[list[Stream], list[Stream]]: ) -> tuple[list[Stream], list[Stream]]:
"""Converts list of dicts to a list of Streams, validating input in the process """Converts list of dicts to a list of Streams, validating input in the process
@@ -1386,7 +1390,7 @@ def list_to_streams(
realm=user_profile.realm, realm=user_profile.realm,
stream_dicts=missing_stream_dicts, stream_dicts=missing_stream_dicts,
acting_user=user_profile, acting_user=user_profile,
setting_groups_dict=setting_groups_dict, anonymous_group_membership=anonymous_group_membership,
) )
existing_streams += dup_streams existing_streams += dup_streams
@@ -1446,7 +1450,7 @@ def get_stream_post_policy_value_based_on_group_setting(setting_group: UserGroup
def stream_to_dict( def stream_to_dict(
stream: Stream, stream: Stream,
recent_traffic: dict[int, int] | None = None, recent_traffic: dict[int, int] | None = None,
setting_groups_dict: dict[int, int | UserGroupMembersDict] | None = None, anonymous_group_membership: dict[int, UserGroupMembersDict] | None = None,
) -> APIStreamDict: ) -> APIStreamDict:
if recent_traffic is not None: if recent_traffic is not None:
stream_weekly_traffic = get_average_weekly_stream_traffic( stream_weekly_traffic = get_average_weekly_stream_traffic(
@@ -1461,12 +1465,22 @@ def stream_to_dict(
# passing stream data to spectators. # passing stream data to spectators.
stream_weekly_traffic = None stream_weekly_traffic = None
assert setting_groups_dict is not None assert anonymous_group_membership is not None
can_add_subscribers_group = setting_groups_dict[stream.can_add_subscribers_group_id] can_add_subscribers_group = get_group_setting_value_for_register_api(
can_administer_channel_group = setting_groups_dict[stream.can_administer_channel_group_id] stream.can_add_subscribers_group_id, anonymous_group_membership
can_send_message_group = setting_groups_dict[stream.can_send_message_group_id] )
can_remove_subscribers_group = setting_groups_dict[stream.can_remove_subscribers_group_id] can_administer_channel_group = get_group_setting_value_for_register_api(
can_subscribe_group = setting_groups_dict[stream.can_subscribe_group_id] stream.can_administer_channel_group_id, anonymous_group_membership
)
can_send_message_group = get_group_setting_value_for_register_api(
stream.can_send_message_group_id, anonymous_group_membership
)
can_remove_subscribers_group = get_group_setting_value_for_register_api(
stream.can_remove_subscribers_group_id, anonymous_group_membership
)
can_subscribe_group = get_group_setting_value_for_register_api(
stream.can_subscribe_group_id, anonymous_group_membership
)
stream_post_policy = get_stream_post_policy_value_based_on_group_setting( stream_post_policy = get_stream_post_policy_value_based_on_group_setting(
stream.can_send_message_group stream.can_send_message_group
@@ -1500,8 +1514,8 @@ def stream_to_dict(
def get_web_public_streams(realm: Realm) -> list[APIStreamDict]: # nocoverage def get_web_public_streams(realm: Realm) -> list[APIStreamDict]: # nocoverage
query = get_web_public_streams_queryset(realm) query = get_web_public_streams_queryset(realm)
streams = query.only(*Stream.API_FIELDS) streams = query.only(*Stream.API_FIELDS)
setting_groups_dict = get_group_setting_value_dict_for_streams(list(streams)) anonymous_group_membership = get_anonymous_group_membership_dict_for_streams(list(streams))
stream_dicts = [stream_to_dict(stream, None, setting_groups_dict) for stream in streams] stream_dicts = [stream_to_dict(stream, None, anonymous_group_membership) for stream in streams]
return stream_dicts return stream_dicts
@@ -1623,38 +1637,23 @@ def get_streams_for_user(
return list(streams) return list(streams)
def get_group_setting_value_dict_for_streams( def get_anonymous_group_membership_dict_for_streams(
streams: list[Stream], streams: list[Stream],
) -> dict[int, int | UserGroupMembersDict]: ) -> dict[int, UserGroupMembersDict]:
setting_group_ids = set() setting_group_ids = set()
for stream in streams: for stream in streams:
for setting_name in Stream.stream_permission_group_settings: for setting_name in Stream.stream_permission_group_settings:
setting_group_ids.add(getattr(stream, setting_name + "_id")) setting_group_ids.add(getattr(stream, setting_name + "_id"))
return get_setting_values_for_group_settings(list(setting_group_ids)) anonymous_groups_membership_dict: dict[int, UserGroupMembersDict] = dict()
def get_setting_values_for_group_settings(
group_ids: list[int],
) -> dict[int, int | UserGroupMembersDict]:
user_groups = UserGroup.objects.filter(id__in=group_ids).select_related("named_user_group")
setting_groups_dict: dict[int, int | UserGroupMembersDict] = dict()
anonymous_group_ids = set()
for group in user_groups:
if hasattr(group, "named_user_group"):
setting_groups_dict[group.id] = group.id
else:
anonymous_group_ids.add(group.id)
anonymous_group_ids = UserGroup.objects.filter(
id__in=setting_group_ids, named_user_group=None
).values_list("id", flat=True)
if len(anonymous_group_ids) == 0: if len(anonymous_group_ids) == 0:
return setting_groups_dict return anonymous_groups_membership_dict
group_members_dict = get_members_and_subgroups_of_groups(anonymous_group_ids) return get_members_and_subgroups_of_groups(anonymous_group_ids)
for group_id in anonymous_group_ids:
setting_groups_dict[group_id] = group_members_dict[group_id]
return setting_groups_dict
def do_get_streams( def do_get_streams(
@@ -1684,10 +1683,10 @@ def do_get_streams(
stream_ids = {stream.id for stream in streams} stream_ids = {stream.id for stream in streams}
recent_traffic = get_streams_traffic(stream_ids, user_profile.realm) recent_traffic = get_streams_traffic(stream_ids, user_profile.realm)
setting_groups_dict = get_group_setting_value_dict_for_streams(streams) anonymous_group_membership = get_anonymous_group_membership_dict_for_streams(streams)
stream_dicts = sorted( stream_dicts = sorted(
(stream_to_dict(stream, recent_traffic, setting_groups_dict) for stream in streams), (stream_to_dict(stream, recent_traffic, anonymous_group_membership) for stream in streams),
key=lambda elt: elt["name"], key=lambda elt: elt["name"],
) )

View File

@@ -19,8 +19,7 @@ from zerver.lib.stream_subscription import (
) )
from zerver.lib.stream_traffic import get_average_weekly_stream_traffic, get_streams_traffic from zerver.lib.stream_traffic import get_average_weekly_stream_traffic, get_streams_traffic
from zerver.lib.streams import ( from zerver.lib.streams import (
get_group_setting_value_dict_for_streams, get_anonymous_group_membership_dict_for_streams,
get_setting_values_for_group_settings,
get_stream_post_policy_value_based_on_group_setting, get_stream_post_policy_value_based_on_group_setting,
get_users_dict_with_metadata_access_to_streams_via_permission_groups, get_users_dict_with_metadata_access_to_streams_via_permission_groups,
get_web_public_streams_queryset, get_web_public_streams_queryset,
@@ -37,8 +36,13 @@ from zerver.lib.types import (
SubscriptionStreamDict, SubscriptionStreamDict,
UserGroupMembersDict, UserGroupMembersDict,
) )
from zerver.lib.user_groups import UserGroupMembershipDetails, get_recursive_membership_groups from zerver.lib.user_groups import (
from zerver.models import Realm, Stream, Subscription, UserProfile UserGroupMembershipDetails,
get_group_setting_value_for_register_api,
get_members_and_subgroups_of_groups,
get_recursive_membership_groups,
)
from zerver.models import Realm, Stream, Subscription, UserGroup, UserProfile
from zerver.models.streams import get_all_streams from zerver.models.streams import get_all_streams
@@ -53,16 +57,26 @@ def get_web_public_subs(realm: Realm) -> SubscriptionInfo:
subscribed = [] subscribed = []
streams = get_web_public_streams_queryset(realm) streams = get_web_public_streams_queryset(realm)
setting_groups_dict = get_group_setting_value_dict_for_streams(list(streams)) anonymous_group_membership = get_anonymous_group_membership_dict_for_streams(list(streams))
for stream in streams: for stream in streams:
# Add Stream fields. # Add Stream fields.
is_archived = stream.deactivated is_archived = stream.deactivated
can_add_subscribers_group = setting_groups_dict[stream.can_add_subscribers_group_id] can_add_subscribers_group = get_group_setting_value_for_register_api(
can_administer_channel_group = setting_groups_dict[stream.can_administer_channel_group_id] stream.can_add_subscribers_group_id, anonymous_group_membership
can_send_message_group = setting_groups_dict[stream.can_send_message_group_id] )
can_remove_subscribers_group = setting_groups_dict[stream.can_remove_subscribers_group_id] can_administer_channel_group = get_group_setting_value_for_register_api(
can_subscribe_group = setting_groups_dict[stream.can_subscribe_group_id] stream.can_administer_channel_group_id, anonymous_group_membership
)
can_send_message_group = get_group_setting_value_for_register_api(
stream.can_send_message_group_id, anonymous_group_membership
)
can_remove_subscribers_group = get_group_setting_value_for_register_api(
stream.can_remove_subscribers_group_id, anonymous_group_membership
)
can_subscribe_group = get_group_setting_value_for_register_api(
stream.can_subscribe_group_id, anonymous_group_membership
)
creator_id = stream.creator_id creator_id = stream.creator_id
date_created = datetime_to_timestamp(stream.date_created) date_created = datetime_to_timestamp(stream.date_created)
description = stream.description description = stream.description
@@ -147,7 +161,7 @@ def build_unsubscribed_sub_from_stream_dict(
def build_stream_api_dict( def build_stream_api_dict(
raw_stream_dict: RawStreamDict, raw_stream_dict: RawStreamDict,
recent_traffic: dict[int, int] | None, recent_traffic: dict[int, int] | None,
setting_groups_dict: dict[int, int | UserGroupMembersDict], anonymous_group_membership: dict[int, UserGroupMembersDict],
) -> APIStreamDict: ) -> APIStreamDict:
# Add a few computed fields not directly from the data models. # Add a few computed fields not directly from the data models.
if recent_traffic is not None: if recent_traffic is not None:
@@ -162,15 +176,21 @@ def build_stream_api_dict(
# migration. # migration.
is_announcement_only = raw_stream_dict["stream_post_policy"] == Stream.STREAM_POST_POLICY_ADMINS is_announcement_only = raw_stream_dict["stream_post_policy"] == Stream.STREAM_POST_POLICY_ADMINS
can_add_subscribers_group = setting_groups_dict[raw_stream_dict["can_add_subscribers_group_id"]] can_add_subscribers_group = get_group_setting_value_for_register_api(
can_administer_channel_group = setting_groups_dict[ raw_stream_dict["can_add_subscribers_group_id"], anonymous_group_membership
raw_stream_dict["can_administer_channel_group_id"] )
] can_administer_channel_group = get_group_setting_value_for_register_api(
can_send_message_group = setting_groups_dict[raw_stream_dict["can_send_message_group_id"]] raw_stream_dict["can_administer_channel_group_id"], anonymous_group_membership
can_remove_subscribers_group = setting_groups_dict[ )
raw_stream_dict["can_remove_subscribers_group_id"] can_send_message_group = get_group_setting_value_for_register_api(
] raw_stream_dict["can_send_message_group_id"], anonymous_group_membership
can_subscribe_group = setting_groups_dict[raw_stream_dict["can_subscribe_group_id"]] )
can_remove_subscribers_group = get_group_setting_value_for_register_api(
raw_stream_dict["can_remove_subscribers_group_id"], anonymous_group_membership
)
can_subscribe_group = get_group_setting_value_for_register_api(
raw_stream_dict["can_subscribe_group_id"], anonymous_group_membership
)
return APIStreamDict( return APIStreamDict(
is_archived=raw_stream_dict["deactivated"], is_archived=raw_stream_dict["deactivated"],
@@ -277,7 +297,7 @@ def build_stream_dict_for_sub(
def build_stream_dict_for_never_sub( def build_stream_dict_for_never_sub(
raw_stream_dict: RawStreamDict, raw_stream_dict: RawStreamDict,
recent_traffic: dict[int, int] | None, recent_traffic: dict[int, int] | None,
setting_groups_dict: dict[int, int | UserGroupMembersDict], anonymous_group_membership: dict[int, UserGroupMembersDict],
) -> NeverSubscribedStreamDict: ) -> NeverSubscribedStreamDict:
is_archived = raw_stream_dict["deactivated"] is_archived = raw_stream_dict["deactivated"]
creator_id = raw_stream_dict["creator_id"] creator_id = raw_stream_dict["creator_id"]
@@ -301,17 +321,21 @@ def build_stream_dict_for_never_sub(
else: else:
stream_weekly_traffic = None stream_weekly_traffic = None
can_add_subscribers_group_value = setting_groups_dict[ can_add_subscribers_group_value = get_group_setting_value_for_register_api(
raw_stream_dict["can_add_subscribers_group_id"] raw_stream_dict["can_add_subscribers_group_id"], anonymous_group_membership
] )
can_administer_channel_group_value = setting_groups_dict[ can_administer_channel_group_value = get_group_setting_value_for_register_api(
raw_stream_dict["can_administer_channel_group_id"] raw_stream_dict["can_administer_channel_group_id"], anonymous_group_membership
] )
can_send_message_group_value = setting_groups_dict[raw_stream_dict["can_send_message_group_id"]] can_send_message_group_value = get_group_setting_value_for_register_api(
can_remove_subscribers_group_value = setting_groups_dict[ raw_stream_dict["can_send_message_group_id"], anonymous_group_membership
raw_stream_dict["can_remove_subscribers_group_id"] )
] can_remove_subscribers_group_value = get_group_setting_value_for_register_api(
can_subscribe_group_value = setting_groups_dict[raw_stream_dict["can_subscribe_group_id"]] raw_stream_dict["can_remove_subscribers_group_id"], anonymous_group_membership
)
can_subscribe_group_value = get_group_setting_value_for_register_api(
raw_stream_dict["can_subscribe_group_id"], anonymous_group_membership
)
# Backwards-compatibility addition of removed field. # Backwards-compatibility addition of removed field.
is_announcement_only = raw_stream_dict["stream_post_policy"] == Stream.STREAM_POST_POLICY_ADMINS is_announcement_only = raw_stream_dict["stream_post_policy"] == Stream.STREAM_POST_POLICY_ADMINS
@@ -654,8 +678,10 @@ def gather_subscriptions_helper(
for stream_dict in all_stream_dicts: for stream_dict in all_stream_dicts:
for setting_name in Stream.stream_permission_group_settings: for setting_name in Stream.stream_permission_group_settings:
setting_group_ids.add(stream_dict[setting_name + "_id"]) setting_group_ids.add(stream_dict[setting_name + "_id"])
anonymous_group_ids = UserGroup.objects.filter(
setting_groups_dict = get_setting_values_for_group_settings(list(setting_group_ids)) id__in=setting_group_ids, named_user_group=None
).values_list("id", flat=True)
anonymous_group_membership = get_members_and_subgroups_of_groups(set(anonymous_group_ids))
sub_dicts_query: Iterable[RawSubscriptionDict] = ( sub_dicts_query: Iterable[RawSubscriptionDict] = (
get_stream_subscriptions_for_user(user_profile) get_stream_subscriptions_for_user(user_profile)
@@ -703,7 +729,7 @@ def gather_subscriptions_helper(
sub_unsub_stream_ids.add(stream_id) sub_unsub_stream_ids.add(stream_id)
raw_stream_dict = all_streams_map[stream_id] raw_stream_dict = all_streams_map[stream_id]
stream_api_dict = build_stream_api_dict( stream_api_dict = build_stream_api_dict(
raw_stream_dict, recent_traffic, setting_groups_dict raw_stream_dict, recent_traffic, anonymous_group_membership
) )
stream_dict = build_stream_dict_for_sub( stream_dict = build_stream_dict_for_sub(
user=user_profile, user=user_profile,
@@ -764,7 +790,7 @@ def gather_subscriptions_helper(
slim_stream_dict = build_stream_dict_for_never_sub( slim_stream_dict = build_stream_dict_for_never_sub(
raw_stream_dict=raw_stream_dict, raw_stream_dict=raw_stream_dict,
recent_traffic=recent_traffic, recent_traffic=recent_traffic,
setting_groups_dict=setting_groups_dict, anonymous_group_membership=anonymous_group_membership,
) )
never_subscribed.append(slim_stream_dict) never_subscribed.append(slim_stream_dict)

View File

@@ -70,7 +70,7 @@ from zerver.lib.streams import (
check_stream_name_available, check_stream_name_available,
do_get_streams, do_get_streams,
filter_stream_authorization_for_adding_subscribers, filter_stream_authorization_for_adding_subscribers,
get_group_setting_value_dict_for_streams, get_anonymous_group_membership_dict_for_streams,
get_stream_permission_default_group, get_stream_permission_default_group,
get_stream_permission_policy_name, get_stream_permission_policy_name,
list_to_streams, list_to_streams,
@@ -619,7 +619,7 @@ def add_subscriptions_backend(
if principals is None: if principals is None:
principals = [] principals = []
setting_groups_dict = {} anonymous_group_membership = {}
group_settings_map = {} group_settings_map = {}
request_settings_dict = locals() request_settings_dict = locals()
# We don't want to calculate this value if no default values are # We don't want to calculate this value if no default values are
@@ -640,7 +640,8 @@ def add_subscriptions_backend(
setting_name=setting_name, setting_name=setting_name,
permission_configuration=permission_configuration, permission_configuration=permission_configuration,
) )
setting_groups_dict[group_settings_map[setting_name].id] = setting_value if not isinstance(setting_value, int):
anonymous_group_membership[group_settings_map[setting_name].id] = setting_value
else: else:
if system_groups_name_dict is None: if system_groups_name_dict is None:
system_groups_name_dict = get_role_based_system_groups_dict(realm) system_groups_name_dict = get_role_based_system_groups_dict(realm)
@@ -650,13 +651,9 @@ def add_subscriptions_backend(
if permission_configuration.default_group_name == "stream_creator_or_nobody": if permission_configuration.default_group_name == "stream_creator_or_nobody":
# Default for some settings like "can_administer_channel_group" # Default for some settings like "can_administer_channel_group"
# is anonymous group with stream creator. # is anonymous group with stream creator.
setting_groups_dict[group_settings_map[setting_name].id] = UserGroupMembersDict( anonymous_group_membership[group_settings_map[setting_name].id] = (
direct_subgroups=[], direct_members=[user_profile.id] UserGroupMembersDict(direct_subgroups=[], direct_members=[user_profile.id])
) )
else:
setting_groups_dict[group_settings_map[setting_name].id] = group_settings_map[
setting_name
].id
for stream_obj in streams_raw: for stream_obj in streams_raw:
# 'color' field is optional # 'color' field is optional
@@ -703,7 +700,7 @@ def add_subscriptions_backend(
user_profile, user_profile,
autocreate=True, autocreate=True,
is_default_stream=is_default_stream, is_default_stream=is_default_stream,
setting_groups_dict=setting_groups_dict, anonymous_group_membership=anonymous_group_membership,
) )
streams_categorized_by_permissions = filter_stream_authorization_for_adding_subscribers( streams_categorized_by_permissions = filter_stream_authorization_for_adding_subscribers(
@@ -964,10 +961,10 @@ def get_stream_backend(
(stream, sub) = access_stream_by_id(user_profile, stream_id, require_content_access=False) (stream, sub) = access_stream_by_id(user_profile, stream_id, require_content_access=False)
recent_traffic = get_streams_traffic({stream.id}, user_profile.realm) recent_traffic = get_streams_traffic({stream.id}, user_profile.realm)
setting_groups_dict = get_group_setting_value_dict_for_streams([stream]) anonymous_group_membership = get_anonymous_group_membership_dict_for_streams([stream])
return json_success( return json_success(
request, data={"stream": stream_to_dict(stream, recent_traffic, setting_groups_dict)} request, data={"stream": stream_to_dict(stream, recent_traffic, anonymous_group_membership)}
) )