get_streams: Add include_can_access_content.

Also add some query count checks.
See https://chat.zulip.org/#narrow/channel/378-api-design/topic/GET.20.2Fstreams.20with.20new.20permissions/with/2096944
for API design discussion.
This commit is contained in:
Shubham Padia
2025-02-24 20:42:03 +00:00
committed by Tim Abbott
parent 19b96ce9a8
commit 6dde44cf37
6 changed files with 159 additions and 25 deletions

View File

@@ -1443,6 +1443,7 @@ def get_streams_for_user(
exclude_archived: bool = True,
include_all_active: bool = False,
include_owner_subscribed: bool = False,
include_can_access_content: bool = False,
) -> list[Stream]:
if include_all_active and not user_profile.is_realm_admin:
raise JsonableError(_("User not authorized for this query"))
@@ -1473,14 +1474,53 @@ def get_streams_for_user(
else:
query_filter |= option
if include_subscribed:
should_add_owner_subscribed_filter = include_owner_subscribed and user_profile.is_bot
if include_can_access_content:
all_streams = list(
query.only(
*Stream.API_FIELDS,
"can_send_message_group",
"can_send_message_group__named_user_group",
# Both of these fields are need for get_content_access_streams.
"is_in_zephyr_realm",
"recipient_id",
)
)
user_group_membership_details = UserGroupMembershipDetails(
user_recursive_group_ids=None
)
content_access_streams = get_content_access_streams(
user_profile, all_streams, user_group_membership_details
)
# Optimization: Currently, only include_owner_subscribed
# has the ability to add additional results to
# content_access_streams. We return early to save us a
# database query down the line if we do not need to add
# include_owner_subscribed filter.
if not should_add_owner_subscribed_filter:
return content_access_streams
content_access_stream_ids = [stream.id for stream in content_access_streams]
content_access_stream_check = Q(id__in=set(content_access_stream_ids))
add_filter_option(content_access_stream_check)
# Subscribed channels will already have been included if
# include_can_access_content is True.
if not include_can_access_content and include_subscribed:
subscribed_stream_ids = get_subscribed_stream_ids_for_user(user_profile)
recipient_check = Q(id__in=set(subscribed_stream_ids))
add_filter_option(recipient_check)
if include_public:
# All accessible public channels will already have been
# included if include_can_access_content is True.
if not include_can_access_content and include_public:
invite_only_check = Q(invite_only=False)
add_filter_option(invite_only_check)
if include_web_public:
# All accessible web-public channels will already have been
# included if include_can_access_content is True.
if not include_can_access_content and include_web_public:
# This should match get_web_public_streams_queryset
web_public_check = Q(
is_web_public=True,
@@ -1489,7 +1529,8 @@ def get_streams_for_user(
deactivated=False,
)
add_filter_option(web_public_check)
if include_owner_subscribed and user_profile.is_bot:
if should_add_owner_subscribed_filter:
bot_owner = user_profile.bot_owner
assert bot_owner is not None
owner_stream_ids = get_subscribed_stream_ids_for_user(bot_owner)
@@ -1576,6 +1617,7 @@ def do_get_streams(
include_all_active: bool = False,
include_default: bool = False,
include_owner_subscribed: bool = False,
include_can_access_content: bool = False,
) -> list[APIStreamDict]:
# This function is only used by API clients now.
@@ -1587,6 +1629,7 @@ def do_get_streams(
exclude_archived,
include_all_active,
include_owner_subscribed,
include_can_access_content,
)
stream_ids = {stream.id for stream in streams}