streams: Allow adding newly created channels to folders.

Fixes part of #31972.
This commit is contained in:
Sahil Batra
2025-05-13 16:38:26 +05:30
committed by Tim Abbott
parent 202bebda89
commit ec96fc9659
5 changed files with 79 additions and 1 deletions

View File

@@ -0,0 +1,2 @@
* [`POST /users/me/subscriptions`](/api/subscribe): Added support to add
newly created channels to folder using `folder_id` parameter.

View File

@@ -35,6 +35,7 @@ from zerver.lib.user_groups import (
user_has_permission_for_group_setting,
)
from zerver.models import (
ChannelFolder,
DefaultStreamGroup,
Message,
NamedUserGroup,
@@ -88,6 +89,7 @@ class StreamDict(TypedDict, total=False):
can_send_message_group: UserGroup | None
can_remove_subscribers_group: UserGroup | None
can_subscribe_group: UserGroup | None
folder: ChannelFolder | None
def get_stream_permission_policy_key(
@@ -265,6 +267,7 @@ def create_stream_if_needed(
can_send_message_group: UserGroup | None = None,
can_remove_subscribers_group: UserGroup | None = None,
can_subscribe_group: UserGroup | None = None,
folder: ChannelFolder | None = None,
acting_user: UserProfile | None = None,
anonymous_group_membership: dict[int, UserGroupMembersData] | None = None,
) -> tuple[Stream, bool]:
@@ -304,6 +307,7 @@ def create_stream_if_needed(
history_public_to_subscribers=history_public_to_subscribers,
is_in_zephyr_realm=realm.is_zephyr_mirror_realm,
message_retention_days=message_retention_days,
folder=folder,
**group_setting_values,
),
)
@@ -383,6 +387,7 @@ def create_streams_if_needed(
can_send_message_group=stream_dict.get("can_send_message_group", None),
can_remove_subscribers_group=stream_dict.get("can_remove_subscribers_group", None),
can_subscribe_group=stream_dict.get("can_subscribe_group", None),
folder=stream_dict.get("folder", None),
acting_user=acting_user,
anonymous_group_membership=anonymous_group_membership,
)

View File

@@ -11219,6 +11219,17 @@ paths:
$ref: "#/components/schemas/CanSendMessageGroup"
can_subscribe_group:
$ref: "#/components/schemas/CanSubscribeGroup"
folder_id:
description: |
This parameter determines the folder to which the newly
created channel will be added.
If the value is `None`, the channel will not be added to
any folder.
**Changes**: New in Zulip 11.0 (feature level ZF-919531).
type: integer
example: 1
required:
- subscriptions
encoding:
@@ -11248,6 +11259,8 @@ paths:
contentType: application/json
can_subscribe_group:
contentType: application/json
folder_id:
contentType: application/json
responses:
"200":
description: Success.

View File

@@ -15,6 +15,7 @@ from django.utils.timezone import now as timezone_now
from typing_extensions import override
from zerver.actions.bots import do_change_bot_owner
from zerver.actions.channel_folders import check_add_channel_folder
from zerver.actions.create_realm import do_create_realm
from zerver.actions.default_streams import (
do_add_default_stream,
@@ -952,6 +953,56 @@ class TestCreateStreams(ZulipTestCase):
self.assert_length(channel_events_messages, 1)
self.assertIn(policy_key_map[policy_key], channel_events_messages[0].content)
def test_adding_channels_to_folder_during_creation(self) -> None:
realm = get_realm("zulip")
iago = self.example_user("iago")
hamlet = self.example_user("hamlet")
channel_folder = check_add_channel_folder("Backend", "", acting_user=iago)
subscriptions = [
{"name": "new_stream", "description": "New stream"},
{"name": "new_stream_2", "description": "New stream 2"},
]
extra_post_data = {}
extra_post_data["folder_id"] = orjson.dumps(99).decode()
result = self.subscribe_via_post(
hamlet,
subscriptions,
extra_post_data,
allow_fail=True,
subdomain="zulip",
)
self.assert_json_error(result, "Invalid channel folder ID")
extra_post_data["folder_id"] = orjson.dumps(channel_folder.id).decode()
result = self.subscribe_via_post(
hamlet,
subscriptions,
extra_post_data,
subdomain="zulip",
)
stream = get_stream("new_stream", realm)
self.assertEqual(stream.folder, channel_folder)
stream = get_stream("new_stream_2", realm)
self.assertEqual(stream.folder, channel_folder)
subscriptions = [
{"name": "new_stream_3", "description": "New stream 3"},
{"name": "new_stream_4", "description": "New stream 4"},
]
extra_post_data = {}
result = self.subscribe_via_post(
hamlet,
subscriptions,
extra_post_data,
subdomain="zulip",
)
stream = get_stream("new_stream_3", realm)
self.assertIsNone(stream.folder)
stream = get_stream("new_stream_4", realm)
self.assertIsNone(stream.folder)
class RecipientTest(ZulipTestCase):
def test_recipient(self) -> None:

View File

@@ -48,6 +48,7 @@ from zerver.decorator import (
require_non_guest_user,
require_realm_admin,
)
from zerver.lib.channel_folders import get_channel_folder_by_id
from zerver.lib.default_streams import get_default_stream_ids_for_realm
from zerver.lib.email_mirror_helpers import encode_email_address, get_channel_email_token
from zerver.lib.exceptions import (
@@ -103,7 +104,7 @@ from zerver.lib.user_groups import (
from zerver.lib.user_topics import get_users_with_user_topic_visibility_policy
from zerver.lib.users import access_bot_by_id, bulk_access_users_by_email, bulk_access_users_by_id
from zerver.lib.utils import assert_is_not_none
from zerver.models import Realm, Stream, UserMessage, UserProfile, UserTopic
from zerver.models import ChannelFolder, Realm, Stream, UserMessage, UserProfile, UserTopic
from zerver.models.groups import SystemGroups
from zerver.models.users import get_system_bot
@@ -624,6 +625,7 @@ def add_subscriptions_backend(
announce: Json[bool] = False,
principals: Json[list[str] | list[int]] | None = None,
authorization_errors_fatal: Json[bool] = True,
folder_id: Json[int] | None = None,
) -> HttpResponse:
realm = user_profile.realm
stream_dicts = []
@@ -668,6 +670,10 @@ def add_subscriptions_backend(
UserGroupMembersData(direct_subgroups=[], direct_members=[user_profile.id])
)
folder: ChannelFolder | None = None
if folder_id is not None:
folder = get_channel_folder_by_id(folder_id, realm)
for stream_obj in streams_raw:
# 'color' field is optional
# check for its presence in the streams_raw first
@@ -698,6 +704,7 @@ def add_subscriptions_backend(
"can_remove_subscribers_group"
]
stream_dict_copy["can_subscribe_group"] = group_settings_map["can_subscribe_group"]
stream_dict_copy["folder"] = folder
stream_dicts.append(stream_dict_copy)