subscription: Refactor code for creating subscription dicts.

This commit refactors code to create subscription dicts so
that we can efficiently compute can_remove_subscribers_group
setting when we add support to set the setting to anonymous
groups.
This commit is contained in:
Sahil Batra 2024-11-01 16:36:00 +05:30 committed by Tim Abbott
parent 6bd322ac5d
commit 10ae4ffea4
1 changed files with 58 additions and 57 deletions

View File

@ -17,7 +17,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 get_web_public_streams_queryset, subscribed_to_stream from zerver.lib.streams import get_web_public_streams_queryset, subscribed_to_stream
from zerver.lib.timestamp import datetime_to_timestamp, timestamp_to_datetime from zerver.lib.timestamp import datetime_to_timestamp
from zerver.lib.types import ( from zerver.lib.types import (
APIStreamDict, APIStreamDict,
NeverSubscribedStreamDict, NeverSubscribedStreamDict,
@ -112,55 +112,69 @@ def get_web_public_subs(realm: Realm) -> SubscriptionInfo:
def build_unsubscribed_sub_from_stream_dict( def build_unsubscribed_sub_from_stream_dict(
user: UserProfile, sub_dict: RawSubscriptionDict, stream_dict: APIStreamDict user: UserProfile, sub_dict: RawSubscriptionDict, stream_dict: APIStreamDict
) -> SubscriptionStreamDict: ) -> SubscriptionStreamDict:
# This function is only called from `apply_event` code. subscription_stream_dict = build_stream_dict_for_sub(user, sub_dict, stream_dict)
raw_stream_dict = RawStreamDict(
can_remove_subscribers_group_id=stream_dict["can_remove_subscribers_group"],
creator_id=stream_dict["creator_id"],
date_created=timestamp_to_datetime(stream_dict["date_created"]),
deactivated=stream_dict["is_archived"],
description=stream_dict["description"],
first_message_id=stream_dict["first_message_id"],
history_public_to_subscribers=stream_dict["history_public_to_subscribers"],
invite_only=stream_dict["invite_only"],
is_web_public=stream_dict["is_web_public"],
message_retention_days=stream_dict["message_retention_days"],
name=stream_dict["name"],
rendered_description=stream_dict["rendered_description"],
id=stream_dict["stream_id"],
stream_post_policy=stream_dict["stream_post_policy"],
)
# We pass recent_traffic as None and avoid extra database query since we
# already have the traffic data from stream_dict sent with creation event.
subscription_stream_dict = build_stream_dict_for_sub(
user, sub_dict, raw_stream_dict, recent_traffic=None
)
subscription_stream_dict["stream_weekly_traffic"] = stream_dict["stream_weekly_traffic"]
return subscription_stream_dict return subscription_stream_dict
def build_stream_api_dict(
raw_stream_dict: RawStreamDict, recent_traffic: dict[int, int] | None
) -> APIStreamDict:
# Add a few computed fields not directly from the data models.
if recent_traffic is not None:
stream_weekly_traffic = get_average_weekly_stream_traffic(
raw_stream_dict["id"], raw_stream_dict["date_created"], recent_traffic
)
else:
stream_weekly_traffic = None
# Backwards-compatibility for clients that haven't been
# updated for the is_announcement_only -> stream_post_policy
# migration.
is_announcement_only = raw_stream_dict["stream_post_policy"] == Stream.STREAM_POST_POLICY_ADMINS
return APIStreamDict(
is_archived=raw_stream_dict["deactivated"],
can_remove_subscribers_group=raw_stream_dict["can_remove_subscribers_group_id"],
creator_id=raw_stream_dict["creator_id"],
date_created=datetime_to_timestamp(raw_stream_dict["date_created"]),
description=raw_stream_dict["description"],
first_message_id=raw_stream_dict["first_message_id"],
history_public_to_subscribers=raw_stream_dict["history_public_to_subscribers"],
invite_only=raw_stream_dict["invite_only"],
is_web_public=raw_stream_dict["is_web_public"],
message_retention_days=raw_stream_dict["message_retention_days"],
name=raw_stream_dict["name"],
rendered_description=raw_stream_dict["rendered_description"],
stream_id=raw_stream_dict["id"],
stream_post_policy=raw_stream_dict["stream_post_policy"],
stream_weekly_traffic=stream_weekly_traffic,
is_announcement_only=is_announcement_only,
)
def build_stream_dict_for_sub( def build_stream_dict_for_sub(
user: UserProfile, user: UserProfile,
sub_dict: RawSubscriptionDict, sub_dict: RawSubscriptionDict,
raw_stream_dict: RawStreamDict, stream_dict: APIStreamDict,
recent_traffic: dict[int, int] | None,
) -> SubscriptionStreamDict: ) -> SubscriptionStreamDict:
# Handle Stream.API_FIELDS # Handle Stream.API_FIELDS
is_archived = raw_stream_dict["deactivated"] is_archived = stream_dict["is_archived"]
can_remove_subscribers_group_id = raw_stream_dict["can_remove_subscribers_group_id"] can_remove_subscribers_group = stream_dict["can_remove_subscribers_group"]
creator_id = raw_stream_dict["creator_id"] creator_id = stream_dict["creator_id"]
date_created = datetime_to_timestamp(raw_stream_dict["date_created"]) date_created = stream_dict["date_created"]
description = raw_stream_dict["description"] description = stream_dict["description"]
first_message_id = raw_stream_dict["first_message_id"] first_message_id = stream_dict["first_message_id"]
history_public_to_subscribers = raw_stream_dict["history_public_to_subscribers"] history_public_to_subscribers = stream_dict["history_public_to_subscribers"]
invite_only = raw_stream_dict["invite_only"] invite_only = stream_dict["invite_only"]
is_web_public = raw_stream_dict["is_web_public"] is_web_public = stream_dict["is_web_public"]
message_retention_days = raw_stream_dict["message_retention_days"] message_retention_days = stream_dict["message_retention_days"]
name = raw_stream_dict["name"] name = stream_dict["name"]
rendered_description = raw_stream_dict["rendered_description"] rendered_description = stream_dict["rendered_description"]
stream_id = raw_stream_dict["id"] stream_id = stream_dict["stream_id"]
stream_post_policy = raw_stream_dict["stream_post_policy"] stream_post_policy = stream_dict["stream_post_policy"]
stream_weekly_traffic = stream_dict["stream_weekly_traffic"]
is_announcement_only = stream_dict["is_announcement_only"]
# Handle Subscription.API_FIELDS. # Handle Subscription.API_FIELDS.
color = sub_dict["color"] color = sub_dict["color"]
@ -176,24 +190,11 @@ def build_stream_dict_for_sub(
# updated for the in_home_view => is_muted API migration. # updated for the in_home_view => is_muted API migration.
in_home_view = not is_muted in_home_view = not is_muted
# Backwards-compatibility for clients that haven't been
# updated for the is_announcement_only -> stream_post_policy
# migration.
is_announcement_only = raw_stream_dict["stream_post_policy"] == Stream.STREAM_POST_POLICY_ADMINS
# Add a few computed fields not directly from the data models.
if recent_traffic is not None:
stream_weekly_traffic = get_average_weekly_stream_traffic(
raw_stream_dict["id"], raw_stream_dict["date_created"], recent_traffic
)
else:
stream_weekly_traffic = None
# Our caller may add a subscribers field. # Our caller may add a subscribers field.
return SubscriptionStreamDict( return SubscriptionStreamDict(
is_archived=is_archived, is_archived=is_archived,
audible_notifications=audible_notifications, audible_notifications=audible_notifications,
can_remove_subscribers_group=can_remove_subscribers_group_id, can_remove_subscribers_group=can_remove_subscribers_group,
color=color, color=color,
creator_id=creator_id, creator_id=creator_id,
date_created=date_created, date_created=date_created,
@ -504,11 +505,11 @@ def gather_subscriptions_helper(
stream_id = get_stream_id(sub_dict) stream_id = get_stream_id(sub_dict)
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(raw_stream_dict, recent_traffic)
stream_dict = build_stream_dict_for_sub( stream_dict = build_stream_dict_for_sub(
user=user_profile, user=user_profile,
sub_dict=sub_dict, sub_dict=sub_dict,
raw_stream_dict=raw_stream_dict, stream_dict=stream_api_dict,
recent_traffic=recent_traffic,
) )
# is_active is represented in this structure by which list we include it in. # is_active is represented in this structure by which list we include it in.