mirror of
https://github.com/zulip/zulip.git
synced 2025-11-03 05:23:35 +00:00
get_stream_topics: Add support for empty topic name.
This commit is a part of the work to support empty
string as a topic name.
Previously, empty string was not a valid topic name.
Adds `allow_empty_topic_name` boolean parameter to
`GET /users/me/{stream_id}/topics` endpoint to decide
whether the topic names in the fetched `topics` array
can be empty strings.
If False, the topic names in the fetched response will
have the value of `realm_empty_topic_display_name` field
in `POST /register` response replacing "".
Fixes part of #23291.
This commit is contained in:
committed by
Tim Abbott
parent
a76042ce39
commit
181572021d
@@ -124,6 +124,10 @@ deactivated groups.
|
||||
Added `allow_empty_topic_name` boolean parameter to decide whether the
|
||||
topic names in the fetched message history objects can be empty strings.
|
||||
|
||||
* [`GET /users/me/{stream_id}/topics`](/api/get-stream-topics):
|
||||
Added `allow_empty_topic_name` boolean parameter to decide whether the
|
||||
topic names in the fetched `topics` array can be empty strings.
|
||||
|
||||
* [`POST /register`](/api/register-queue): For clients that don't support
|
||||
the `empty_topic_name` [client capability](/api/register-queue#parameter-client_capabilities),
|
||||
the `topic` field in the `unread_msgs` object and `topic_name` field
|
||||
|
||||
@@ -27,7 +27,7 @@ export function get_server_history(stream_id: number, on_success: () => void): v
|
||||
|
||||
void channel.get({
|
||||
url,
|
||||
data: {},
|
||||
data: {allow_empty_topic_name: true},
|
||||
success(raw_data) {
|
||||
const data = stream_topic_history_response_schema.parse(raw_data);
|
||||
const server_history = data.topics;
|
||||
|
||||
@@ -331,7 +331,7 @@ test("server_history_end_to_end", () => {
|
||||
|
||||
channel.get = (opts) => {
|
||||
assert.equal(opts.url, "/json/users/me/99/topics");
|
||||
assert.deepEqual(opts.data, {});
|
||||
assert.deepEqual(opts.data, {allow_empty_topic_name: true});
|
||||
assert.ok(stream_topic_history.is_request_pending_for(stream_id));
|
||||
get_success_callback = opts.success;
|
||||
get_error_callback = opts.error;
|
||||
|
||||
@@ -201,7 +201,10 @@ def update_messages_for_topic_edit(
|
||||
return messages, propagate
|
||||
|
||||
|
||||
def generate_topic_history_from_db_rows(rows: list[tuple[str, int]]) -> list[dict[str, Any]]:
|
||||
def generate_topic_history_from_db_rows(
|
||||
rows: list[tuple[str, int]],
|
||||
allow_empty_topic_name: bool,
|
||||
) -> list[dict[str, Any]]:
|
||||
canonical_topic_names: dict[str, tuple[int, str]] = {}
|
||||
|
||||
# Sort rows by max_message_id so that if a topic
|
||||
@@ -215,13 +218,19 @@ def generate_topic_history_from_db_rows(rows: list[tuple[str, int]]) -> list[dic
|
||||
|
||||
history = []
|
||||
for max_message_id, topic_name in canonical_topic_names.values():
|
||||
if topic_name == "" and not allow_empty_topic_name:
|
||||
topic_name = Message.EMPTY_TOPIC_FALLBACK_NAME
|
||||
history.append(
|
||||
dict(name=topic_name, max_id=max_message_id),
|
||||
)
|
||||
return sorted(history, key=lambda x: -x["max_id"])
|
||||
|
||||
|
||||
def get_topic_history_for_public_stream(realm_id: int, recipient_id: int) -> list[dict[str, Any]]:
|
||||
def get_topic_history_for_public_stream(
|
||||
realm_id: int,
|
||||
recipient_id: int,
|
||||
allow_empty_topic_name: bool,
|
||||
) -> list[dict[str, Any]]:
|
||||
cursor = connection.cursor()
|
||||
# Uses index: zerver_message_realm_recipient_subject
|
||||
# Note that this is *case-sensitive*, so that we can display the
|
||||
@@ -244,14 +253,21 @@ def get_topic_history_for_public_stream(realm_id: int, recipient_id: int) -> lis
|
||||
rows = cursor.fetchall()
|
||||
cursor.close()
|
||||
|
||||
return generate_topic_history_from_db_rows(rows)
|
||||
return generate_topic_history_from_db_rows(rows, allow_empty_topic_name)
|
||||
|
||||
|
||||
def get_topic_history_for_stream(
|
||||
user_profile: UserProfile, recipient_id: int, public_history: bool
|
||||
user_profile: UserProfile,
|
||||
recipient_id: int,
|
||||
public_history: bool,
|
||||
allow_empty_topic_name: bool,
|
||||
) -> list[dict[str, Any]]:
|
||||
if public_history:
|
||||
return get_topic_history_for_public_stream(user_profile.realm_id, recipient_id)
|
||||
return get_topic_history_for_public_stream(
|
||||
user_profile.realm_id,
|
||||
recipient_id,
|
||||
allow_empty_topic_name,
|
||||
)
|
||||
|
||||
cursor = connection.cursor()
|
||||
# Uses index: zerver_message_realm_recipient_subject
|
||||
@@ -279,7 +295,7 @@ def get_topic_history_for_stream(
|
||||
rows = cursor.fetchall()
|
||||
cursor.close()
|
||||
|
||||
return generate_topic_history_from_db_rows(rows)
|
||||
return generate_topic_history_from_db_rows(rows, allow_empty_topic_name)
|
||||
|
||||
|
||||
def get_topic_resolution_and_bare_name(stored_name: str) -> tuple[bool, str]:
|
||||
|
||||
@@ -10220,6 +10220,22 @@ paths:
|
||||
user subscribed.
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/ChannelIdInPath"
|
||||
- name: allow_empty_topic_name
|
||||
in: query
|
||||
description: |
|
||||
Whether the client supports processing the empty string as
|
||||
a topic name in the returned data.
|
||||
|
||||
If `false`, the value of `realm_empty_topic_display_name`
|
||||
found in the [`POST /register`](/api/register-queue) response is
|
||||
returned replacing the empty string as the topic name.
|
||||
|
||||
**Changes**: New in Zulip 10.0 (feature level 334). Previously,
|
||||
the empty string was not a valid topic.
|
||||
schema:
|
||||
type: boolean
|
||||
default: false
|
||||
example: true
|
||||
responses:
|
||||
"200":
|
||||
description: Success.
|
||||
|
||||
@@ -843,3 +843,28 @@ class EmptyTopicNameTest(ZulipTestCase):
|
||||
self.assertEqual(
|
||||
state_data["user_topics"][1]["topic_name"], Message.EMPTY_TOPIC_FALLBACK_NAME
|
||||
)
|
||||
|
||||
def test_get_channel_topics(self) -> None:
|
||||
hamlet = self.example_user("hamlet")
|
||||
self.login_user(hamlet)
|
||||
channel_one = self.make_stream("channel_one")
|
||||
channel_two = self.make_stream("channel_two")
|
||||
self.subscribe(hamlet, channel_one.name)
|
||||
self.subscribe(hamlet, channel_two.name)
|
||||
|
||||
self.send_stream_message(hamlet, channel_one.name, topic_name="")
|
||||
self.send_stream_message(
|
||||
hamlet, channel_two.name, topic_name=Message.EMPTY_TOPIC_FALLBACK_NAME
|
||||
)
|
||||
|
||||
params = {"allow_empty_topic_name": "false"}
|
||||
for channel_id in [channel_one.id, channel_two.id]:
|
||||
result = self.client_get(f"/json/users/me/{channel_id}/topics", params)
|
||||
data = self.assert_json_success(result)
|
||||
self.assertEqual(data["topics"][0]["name"], Message.EMPTY_TOPIC_FALLBACK_NAME)
|
||||
|
||||
params = {"allow_empty_topic_name": "true"}
|
||||
for channel_id in [channel_one.id, channel_two.id]:
|
||||
result = self.client_get(f"/json/users/me/{channel_id}/topics", params)
|
||||
data = self.assert_json_success(result)
|
||||
self.assertEqual(data["topics"][0]["name"], "")
|
||||
|
||||
@@ -929,6 +929,7 @@ def get_topics_backend(
|
||||
maybe_user_profile: UserProfile | AnonymousUser,
|
||||
*,
|
||||
stream_id: PathOnly[NonNegativeInt],
|
||||
allow_empty_topic_name: Json[bool] = False,
|
||||
) -> HttpResponse:
|
||||
if not maybe_user_profile.is_authenticated:
|
||||
is_web_public_query = True
|
||||
@@ -943,7 +944,9 @@ def get_topics_backend(
|
||||
realm = get_valid_realm_from_request(request)
|
||||
stream = access_web_public_stream(stream_id, realm)
|
||||
result = get_topic_history_for_public_stream(
|
||||
realm_id=realm.id, recipient_id=assert_is_not_none(stream.recipient_id)
|
||||
realm_id=realm.id,
|
||||
recipient_id=assert_is_not_none(stream.recipient_id),
|
||||
allow_empty_topic_name=allow_empty_topic_name,
|
||||
)
|
||||
|
||||
else:
|
||||
@@ -956,6 +959,7 @@ def get_topics_backend(
|
||||
user_profile=user_profile,
|
||||
recipient_id=stream.recipient_id,
|
||||
public_history=stream.is_history_public_to_subscribers(),
|
||||
allow_empty_topic_name=allow_empty_topic_name,
|
||||
)
|
||||
|
||||
return json_success(request, data=dict(topics=result))
|
||||
|
||||
Reference in New Issue
Block a user