register: Include folder data for web public streams for spectators.

Spectators would only receive data for channel folders that have
at least one web-public stream.
This commit is contained in:
Sahil Batra
2025-05-16 15:36:28 +05:30
committed by Tim Abbott
parent 509a84403b
commit 222ccac765
4 changed files with 51 additions and 6 deletions

View File

@@ -4,6 +4,7 @@ from django.utils.translation import gettext as _
from zerver.lib.exceptions import JsonableError from zerver.lib.exceptions import JsonableError
from zerver.lib.markdown import markdown_convert from zerver.lib.markdown import markdown_convert
from zerver.lib.streams import get_web_public_streams_queryset
from zerver.lib.string_validation import check_string_is_printable from zerver.lib.string_validation import check_string_is_printable
from zerver.lib.timestamp import datetime_to_timestamp from zerver.lib.timestamp import datetime_to_timestamp
from zerver.models import ChannelFolder, Realm, UserProfile from zerver.models import ChannelFolder, Realm, UserProfile
@@ -71,3 +72,12 @@ def get_channel_folder_by_id(channel_folder_id: int, realm: Realm) -> ChannelFol
return channel_folder return channel_folder
except ChannelFolder.DoesNotExist: except ChannelFolder.DoesNotExist:
raise JsonableError(_("Invalid channel folder ID")) raise JsonableError(_("Invalid channel folder ID"))
def get_channel_folders_for_spectators(realm: Realm) -> list[ChannelFolderDict]:
folder_ids_for_web_public_streams = set(
get_web_public_streams_queryset(realm).values_list("folder_id", flat=True)
)
folders = ChannelFolder.objects.filter(id__in=folder_ids_for_web_public_streams)
channel_folders = [get_channel_folder_dict(channel_folder) for channel_folder in folders]
return sorted(channel_folders, key=lambda folder: folder["id"])

View File

@@ -19,7 +19,10 @@ from zerver.lib import emoji
from zerver.lib.alert_words import user_alert_words from zerver.lib.alert_words import user_alert_words
from zerver.lib.avatar import avatar_url from zerver.lib.avatar import avatar_url
from zerver.lib.bot_config import load_bot_config_template from zerver.lib.bot_config import load_bot_config_template
from zerver.lib.channel_folders import get_channel_folders_in_realm from zerver.lib.channel_folders import (
get_channel_folders_for_spectators,
get_channel_folders_in_realm,
)
from zerver.lib.compatibility import is_outdated_server from zerver.lib.compatibility import is_outdated_server
from zerver.lib.default_streams import get_default_stream_ids_for_realm from zerver.lib.default_streams import get_default_stream_ids_for_realm
from zerver.lib.exceptions import JsonableError from zerver.lib.exceptions import JsonableError
@@ -765,10 +768,11 @@ def fetch_initial_state_data(
state["unsubscribed"] = sub_info.unsubscribed state["unsubscribed"] = sub_info.unsubscribed
state["never_subscribed"] = sub_info.never_subscribed state["never_subscribed"] = sub_info.never_subscribed
if want("channel_folders") and user_profile is not None: if want("channel_folders"):
# TODO: Spectators should get the channel folders that if user_profile is None:
# contain atleast one web-public channel. state["channel_folders"] = get_channel_folders_for_spectators(realm)
state["channel_folders"] = get_channel_folders_in_realm(user_profile.realm, True) else:
state["channel_folders"] = get_channel_folders_in_realm(user_profile.realm, True)
if want("update_message_flags") and want("message"): if want("update_message_flags") and want("message"):
# Keeping unread_msgs updated requires both message flag updates and # Keeping unread_msgs updated requires both message flag updates and

View File

@@ -15915,6 +15915,9 @@ paths:
An array of dictionaries where each dictionary describes one An array of dictionaries where each dictionary describes one
of the channel folders in the organization. of the channel folders in the organization.
Only channel folders with one or more public web channels are
visible to spectators.
**Changes**: New in Zulip 11.0 (feature level ZF-392de9). **Changes**: New in Zulip 11.0 (feature level ZF-392de9).
unread_msgs: unread_msgs:
type: object type: object

View File

@@ -11,9 +11,11 @@ from django.test import override_settings
from django.utils.timezone import now as timezone_now from django.utils.timezone import now as timezone_now
from typing_extensions import override from typing_extensions import override
from zerver.actions.channel_folders import check_add_channel_folder
from zerver.actions.custom_profile_fields import try_update_realm_custom_profile_field from zerver.actions.custom_profile_fields import try_update_realm_custom_profile_field
from zerver.actions.message_send import check_send_message from zerver.actions.message_send import check_send_message
from zerver.actions.presence import do_update_user_presence from zerver.actions.presence import do_update_user_presence
from zerver.actions.streams import do_change_stream_folder
from zerver.actions.user_settings import do_change_user_setting from zerver.actions.user_settings import do_change_user_setting
from zerver.actions.users import do_change_user_role from zerver.actions.users import do_change_user_role
from zerver.lib.event_schema import check_web_reload_client_event from zerver.lib.event_schema import check_web_reload_client_event
@@ -171,7 +173,7 @@ class EventsEndpointTest(ZulipTestCase):
status_code=401, status_code=401,
) )
with self.assert_database_query_count(14): with self.assert_database_query_count(15):
result = self.client_post("/json/register") result = self.client_post("/json/register")
result_dict = self.assert_json_success(result) result_dict = self.assert_json_success(result)
self.assertEqual(result_dict["queue_id"], None) self.assertEqual(result_dict["queue_id"], None)
@@ -198,6 +200,32 @@ class EventsEndpointTest(ZulipTestCase):
status_code=400, status_code=400,
) )
def test_channel_folders_for_spectators(self) -> None:
realm = get_realm("zulip")
iago = self.example_user("iago")
frontend_folder = check_add_channel_folder("Frontend", "", acting_user=iago)
backend_folder = check_add_channel_folder("Backend", "", acting_user=iago)
result = self.client_post("/json/register")
self.assertEqual(result.status_code, 200)
channel_folders_data = orjson.loads(result.content)["channel_folders"]
self.assert_length(channel_folders_data, 0)
web_public_stream = get_stream("Rome", realm)
do_change_stream_folder(web_public_stream, frontend_folder, acting_user=iago)
public_stream = get_stream("Verona", realm)
do_change_stream_folder(public_stream, backend_folder, acting_user=iago)
result = self.client_post("/json/register")
self.assertEqual(result.status_code, 200)
channel_folders_data = orjson.loads(result.content)["channel_folders"]
self.assert_length(channel_folders_data, 1)
self.assertEqual(channel_folders_data[0]["name"], "Frontend")
def test_events_register_endpoint_all_public_streams_access(self) -> None: def test_events_register_endpoint_all_public_streams_access(self) -> None:
guest_user = self.example_user("polonius") guest_user = self.example_user("polonius")
normal_user = self.example_user("hamlet") normal_user = self.example_user("hamlet")