mirror of
https://github.com/zulip/zulip.git
synced 2025-10-23 04:52:12 +00:00
855 lines
33 KiB
Python
855 lines
33 KiB
Python
import time
|
|
from unittest import mock
|
|
|
|
import orjson
|
|
from django.utils.timezone import now as timezone_now
|
|
|
|
from zerver.actions.streams import do_change_stream_permission
|
|
from zerver.actions.user_topics import do_set_user_topic_visibility_policy
|
|
from zerver.lib.events import ClientCapabilities, do_events_register
|
|
from zerver.lib.test_classes import ZulipTestCase
|
|
from zerver.lib.user_topics import set_topic_visibility_policy, topic_has_visibility_policy
|
|
from zerver.models import Message, UserMessage, UserTopic
|
|
from zerver.models.clients import get_client
|
|
from zerver.models.realms import get_realm
|
|
from zerver.models.streams import get_stream
|
|
from zerver.tornado.event_queue import allocate_client_descriptor
|
|
|
|
|
|
class TopicHistoryTest(ZulipTestCase):
|
|
def test_topics_history(self) -> None:
|
|
# verified: int(UserMessage.flags.read) == 1
|
|
user_profile = self.example_user("iago")
|
|
self.login_user(user_profile)
|
|
stream_name = "Verona"
|
|
|
|
stream = get_stream(stream_name, user_profile.realm)
|
|
recipient = stream.recipient
|
|
|
|
def create_test_message(topic_name: str) -> int:
|
|
# TODO: Clean this up to send messages the normal way.
|
|
|
|
hamlet = self.example_user("hamlet")
|
|
message = Message(
|
|
sender=hamlet,
|
|
recipient=recipient,
|
|
realm=stream.realm,
|
|
content="whatever",
|
|
date_sent=timezone_now(),
|
|
sending_client=get_client("whatever"),
|
|
)
|
|
message.set_topic_name(topic_name)
|
|
message.save()
|
|
|
|
UserMessage.objects.create(
|
|
user_profile=user_profile,
|
|
message=message,
|
|
flags=0,
|
|
)
|
|
|
|
return message.id
|
|
|
|
# our most recent topics are topic0, topic1, topic2
|
|
|
|
# Create old messages with strange spellings.
|
|
create_test_message("topic2")
|
|
create_test_message("toPIc1")
|
|
create_test_message("toPIc0")
|
|
create_test_message("topic2")
|
|
create_test_message("topic2")
|
|
create_test_message("Topic2")
|
|
|
|
# Create new messages
|
|
topic2_msg_id = create_test_message("topic2")
|
|
create_test_message("topic1")
|
|
create_test_message("topic1")
|
|
topic1_msg_id = create_test_message("topic1")
|
|
topic0_msg_id = create_test_message("topic0")
|
|
|
|
endpoint = f"/json/users/me/{stream.id}/topics"
|
|
result = self.client_get(endpoint, {})
|
|
history = self.assert_json_success(result)["topics"]
|
|
|
|
# We only look at the most recent three topics, because
|
|
# the prior fixture data may be unreliable.
|
|
history = history[:3]
|
|
|
|
self.assertEqual(
|
|
[topic["name"] for topic in history],
|
|
[
|
|
"topic0",
|
|
"topic1",
|
|
"topic2",
|
|
],
|
|
)
|
|
|
|
self.assertEqual(
|
|
[topic["max_id"] for topic in history],
|
|
[
|
|
topic0_msg_id,
|
|
topic1_msg_id,
|
|
topic2_msg_id,
|
|
],
|
|
)
|
|
|
|
# Now try as cordelia, who we imagine as a totally new user in
|
|
# that she doesn't have UserMessage rows. We should see the
|
|
# same results for a public stream.
|
|
self.login("cordelia")
|
|
result = self.client_get(endpoint, {})
|
|
history = self.assert_json_success(result)["topics"]
|
|
|
|
# We only look at the most recent three topics, because
|
|
# the prior fixture data may be unreliable.
|
|
history = history[:3]
|
|
|
|
self.assertEqual(
|
|
[topic["name"] for topic in history],
|
|
[
|
|
"topic0",
|
|
"topic1",
|
|
"topic2",
|
|
],
|
|
)
|
|
self.assertIn("topic0", [topic["name"] for topic in history])
|
|
|
|
self.assertEqual(
|
|
[topic["max_id"] for topic in history],
|
|
[
|
|
topic0_msg_id,
|
|
topic1_msg_id,
|
|
topic2_msg_id,
|
|
],
|
|
)
|
|
|
|
# Now make stream private, but subscribe cordelia
|
|
do_change_stream_permission(
|
|
stream,
|
|
invite_only=True,
|
|
history_public_to_subscribers=False,
|
|
is_web_public=False,
|
|
acting_user=self.example_user("cordelia"),
|
|
)
|
|
self.subscribe(self.example_user("cordelia"), stream.name)
|
|
|
|
result = self.client_get(endpoint, {})
|
|
history = self.assert_json_success(result)["topics"]
|
|
history = history[:3]
|
|
|
|
# Cordelia doesn't have these recent history items when we
|
|
# wasn't subscribed in her results.
|
|
self.assertNotIn("topic0", [topic["name"] for topic in history])
|
|
self.assertNotIn("topic1", [topic["name"] for topic in history])
|
|
self.assertNotIn("topic2", [topic["name"] for topic in history])
|
|
|
|
def test_bad_stream_id(self) -> None:
|
|
self.login("iago")
|
|
|
|
# non-sensible stream id
|
|
endpoint = "/json/users/me/9999999999/topics"
|
|
result = self.client_get(endpoint, {})
|
|
self.assert_json_error(result, "Invalid channel ID")
|
|
|
|
# out of realm
|
|
bad_stream = self.make_stream(
|
|
"mit_stream",
|
|
realm=get_realm("zephyr"),
|
|
)
|
|
endpoint = f"/json/users/me/{bad_stream.id}/topics"
|
|
result = self.client_get(endpoint, {})
|
|
self.assert_json_error(result, "Invalid channel ID")
|
|
|
|
# private stream to which I am not subscribed
|
|
private_stream = self.make_stream(
|
|
"private_stream",
|
|
invite_only=True,
|
|
)
|
|
endpoint = f"/json/users/me/{private_stream.id}/topics"
|
|
result = self.client_get(endpoint, {})
|
|
self.assert_json_error(result, "Invalid channel ID")
|
|
|
|
def test_get_topics_web_public_stream_web_public_request(self) -> None:
|
|
iago = self.example_user("iago")
|
|
stream = self.make_stream("web-public-stream", is_web_public=True)
|
|
self.subscribe(iago, stream.name)
|
|
|
|
for i in range(3):
|
|
self.send_stream_message(iago, stream.name, topic_name="topic" + str(i))
|
|
|
|
endpoint = f"/json/users/me/{stream.id}/topics"
|
|
result = self.client_get(endpoint)
|
|
history = self.assert_json_success(result)["topics"]
|
|
self.assertEqual(
|
|
[topic["name"] for topic in history],
|
|
[
|
|
"topic2",
|
|
"topic1",
|
|
"topic0",
|
|
],
|
|
)
|
|
|
|
def test_get_topics_non_web_public_stream_web_public_request(self) -> None:
|
|
stream = get_stream("Verona", self.example_user("iago").realm)
|
|
endpoint = f"/json/users/me/{stream.id}/topics"
|
|
result = self.client_get(endpoint)
|
|
self.assert_json_error(result, "Invalid channel ID", 400)
|
|
|
|
def test_get_topics_non_existent_stream_web_public_request(self) -> None:
|
|
non_existent_stream_id = 10000000000000000000000
|
|
endpoint = f"/json/users/me/{non_existent_stream_id}/topics"
|
|
result = self.client_get(endpoint)
|
|
self.assert_json_error(result, "Invalid channel ID", 400)
|
|
|
|
|
|
class TopicDeleteTest(ZulipTestCase):
|
|
def test_topic_delete(self) -> None:
|
|
initial_last_msg_id = self.get_last_message().id
|
|
stream_name = "new_stream"
|
|
topic_name = "new topic 2"
|
|
|
|
# NON-ADMIN USER
|
|
user_profile = self.example_user("hamlet")
|
|
self.subscribe(user_profile, stream_name)
|
|
|
|
# Send message
|
|
stream = get_stream(stream_name, user_profile.realm)
|
|
self.send_stream_message(user_profile, stream_name, topic_name=topic_name)
|
|
last_msg_id = self.send_stream_message(user_profile, stream_name, topic_name=topic_name)
|
|
|
|
# Deleting the topic
|
|
self.login_user(user_profile)
|
|
endpoint = "/json/streams/" + str(stream.id) + "/delete_topic"
|
|
result = self.client_post(
|
|
endpoint,
|
|
{
|
|
"topic_name": topic_name,
|
|
},
|
|
)
|
|
self.assert_json_error(result, "Must be an organization administrator")
|
|
self.assertTrue(Message.objects.filter(id=last_msg_id).exists())
|
|
|
|
# Make stream private with limited history
|
|
do_change_stream_permission(
|
|
stream,
|
|
invite_only=True,
|
|
history_public_to_subscribers=False,
|
|
is_web_public=False,
|
|
acting_user=user_profile,
|
|
)
|
|
|
|
# NON-ADMIN USER follows the topic
|
|
set_topic_visibility_policy(
|
|
user_profile, [[stream_name, topic_name]], UserTopic.VisibilityPolicy.FOLLOWED
|
|
)
|
|
|
|
# ADMIN USER subscribed now and follows the topic
|
|
user_profile = self.example_user("iago")
|
|
self.subscribe(user_profile, stream_name)
|
|
self.login_user(user_profile)
|
|
new_last_msg_id = self.send_stream_message(user_profile, stream_name, topic_name=topic_name)
|
|
set_topic_visibility_policy(
|
|
user_profile, [[stream_name, topic_name]], UserTopic.VisibilityPolicy.FOLLOWED
|
|
)
|
|
|
|
# Now admin deletes all messages in topic -- which should only
|
|
# delete new_last_msg_id, i.e. the one sent since they joined.
|
|
self.assertEqual(self.get_last_message().id, new_last_msg_id)
|
|
result = self.client_post(
|
|
endpoint,
|
|
{
|
|
"topic_name": topic_name,
|
|
},
|
|
)
|
|
result_dict = self.assert_json_success(result)
|
|
self.assertTrue(result_dict["complete"])
|
|
self.assertTrue(Message.objects.filter(id=last_msg_id).exists())
|
|
|
|
# Verify that we delete the UserTopic row only for 'iago' (ADMIN USER) as they can't
|
|
# access any messages in the topic. 'hamlet' (NON ADMIN USER) can still access the
|
|
# protected messages hence the UserTopic row for him is not deleted.
|
|
self.assertTrue(
|
|
topic_has_visibility_policy(
|
|
self.example_user("hamlet"),
|
|
stream.id,
|
|
topic_name,
|
|
UserTopic.VisibilityPolicy.FOLLOWED,
|
|
)
|
|
)
|
|
self.assertFalse(
|
|
topic_has_visibility_policy(
|
|
self.example_user("iago"),
|
|
stream.id,
|
|
topic_name,
|
|
UserTopic.VisibilityPolicy.FOLLOWED,
|
|
)
|
|
)
|
|
|
|
# Try to delete all messages in the topic again. There are no messages accessible
|
|
# to the administrator, so this should do nothing.
|
|
result = self.client_post(
|
|
endpoint,
|
|
{
|
|
"topic_name": topic_name,
|
|
},
|
|
)
|
|
result_dict = self.assert_json_success(result)
|
|
self.assertTrue(result_dict["complete"])
|
|
self.assertTrue(Message.objects.filter(id=last_msg_id).exists())
|
|
|
|
# Make the stream's history public to subscribers
|
|
do_change_stream_permission(
|
|
stream,
|
|
invite_only=True,
|
|
history_public_to_subscribers=True,
|
|
is_web_public=False,
|
|
acting_user=user_profile,
|
|
)
|
|
# Delete the topic should now remove all messages
|
|
result = self.client_post(
|
|
endpoint,
|
|
{
|
|
"topic_name": topic_name,
|
|
},
|
|
)
|
|
result_dict = self.assert_json_success(result)
|
|
self.assertTrue(result_dict["complete"])
|
|
self.assertFalse(Message.objects.filter(id=last_msg_id).exists())
|
|
self.assertTrue(Message.objects.filter(id=initial_last_msg_id).exists())
|
|
|
|
# Delete again, to test the edge case of deleting an empty topic.
|
|
result = self.client_post(
|
|
endpoint,
|
|
{
|
|
"topic_name": topic_name,
|
|
},
|
|
)
|
|
result_dict = self.assert_json_success(result)
|
|
self.assertTrue(result_dict["complete"])
|
|
self.assertFalse(Message.objects.filter(id=last_msg_id).exists())
|
|
self.assertTrue(Message.objects.filter(id=initial_last_msg_id).exists())
|
|
|
|
def test_topic_delete_timeout(self) -> None:
|
|
stream_name = "new_stream"
|
|
topic_name = "new topic 2"
|
|
|
|
user_profile = self.example_user("iago")
|
|
self.subscribe(user_profile, stream_name)
|
|
|
|
stream = get_stream(stream_name, user_profile.realm)
|
|
self.send_stream_message(user_profile, stream_name, topic_name=topic_name)
|
|
|
|
self.login_user(user_profile)
|
|
endpoint = "/json/streams/" + str(stream.id) + "/delete_topic"
|
|
with mock.patch("time.monotonic", side_effect=[10000, 10051]):
|
|
result = self.client_post(
|
|
endpoint,
|
|
{
|
|
"topic_name": topic_name,
|
|
},
|
|
)
|
|
result_dict = self.assert_json_success(result)
|
|
self.assertFalse(result_dict["complete"])
|
|
|
|
|
|
class EmptyTopicNameTest(ZulipTestCase):
|
|
def test_client_supports_empty_topic_name(self) -> None:
|
|
iago = self.example_user("iago")
|
|
hamlet = self.example_user("hamlet")
|
|
queue_data = dict(
|
|
all_public_streams=True,
|
|
apply_markdown=True,
|
|
client_type_name="website",
|
|
empty_topic_name=True,
|
|
event_types=[
|
|
"message",
|
|
"update_message",
|
|
"delete_message",
|
|
"user_topic",
|
|
"typing",
|
|
"update_message_flags",
|
|
],
|
|
last_connection_time=time.time(),
|
|
queue_timeout=600,
|
|
realm_id=hamlet.realm.id,
|
|
stream_typing_notifications=True,
|
|
user_profile_id=hamlet.id,
|
|
)
|
|
client = allocate_client_descriptor(queue_data)
|
|
self.assertTrue(client.event_queue.empty())
|
|
|
|
message_id = self.send_stream_message(iago, "Denmark", topic_name="")
|
|
events = client.event_queue.contents()
|
|
self.assertEqual(events[0]["message"]["subject"], "")
|
|
|
|
message_id_2 = self.send_stream_message(
|
|
iago, "Denmark", topic_name=Message.EMPTY_TOPIC_FALLBACK_NAME
|
|
)
|
|
events = client.event_queue.contents()
|
|
self.assertEqual(events[1]["message"]["subject"], "")
|
|
|
|
self.login_user(iago)
|
|
with self.captureOnCommitCallbacks(execute=True):
|
|
params = {"topic": "new topic name", "send_notification_to_new_thread": "false"}
|
|
self.client_patch(f"/json/messages/{message_id}", params)
|
|
self.client_patch(f"/json/messages/{message_id_2}", params)
|
|
events = client.event_queue.contents()
|
|
self.assertEqual(events[2]["orig_subject"], "")
|
|
self.assertEqual(events[3]["orig_subject"], "")
|
|
|
|
# reset
|
|
message_id = self.send_stream_message(
|
|
iago, "Denmark", topic_name="", skip_capture_on_commit_callbacks=True
|
|
)
|
|
message_id_2 = self.send_stream_message(
|
|
iago,
|
|
"Verona",
|
|
topic_name=Message.EMPTY_TOPIC_FALLBACK_NAME,
|
|
skip_capture_on_commit_callbacks=True,
|
|
)
|
|
|
|
with self.captureOnCommitCallbacks(execute=True):
|
|
self.client_delete(f"/json/messages/{message_id}")
|
|
self.client_delete(f"/json/messages/{message_id_2}")
|
|
events = client.event_queue.contents()
|
|
self.assertEqual(events[4]["topic"], "")
|
|
self.assertEqual(events[5]["topic"], "")
|
|
|
|
# reset
|
|
message_id = self.send_stream_message(
|
|
iago, "Denmark", topic_name="", skip_capture_on_commit_callbacks=True
|
|
)
|
|
message_id_2 = self.send_stream_message(
|
|
iago,
|
|
"Verona",
|
|
topic_name=Message.EMPTY_TOPIC_FALLBACK_NAME,
|
|
skip_capture_on_commit_callbacks=True,
|
|
)
|
|
|
|
self.login_user(hamlet)
|
|
denmark = get_stream("Denmark", hamlet.realm)
|
|
verona = get_stream("Verona", hamlet.realm)
|
|
with self.captureOnCommitCallbacks(execute=True):
|
|
do_set_user_topic_visibility_policy(
|
|
hamlet,
|
|
denmark,
|
|
"",
|
|
visibility_policy=UserTopic.VisibilityPolicy.FOLLOWED,
|
|
)
|
|
do_set_user_topic_visibility_policy(
|
|
hamlet,
|
|
verona,
|
|
Message.EMPTY_TOPIC_FALLBACK_NAME,
|
|
visibility_policy=UserTopic.VisibilityPolicy.FOLLOWED,
|
|
)
|
|
events = client.event_queue.contents()
|
|
self.assertEqual(events[6]["topic_name"], "")
|
|
self.assertEqual(events[7]["topic_name"], "")
|
|
|
|
params = dict(
|
|
type="stream",
|
|
op="start",
|
|
stream_id=str(denmark.id),
|
|
topic="",
|
|
)
|
|
self.api_post(hamlet, "/api/v1/typing", params)
|
|
params = dict(
|
|
type="stream",
|
|
op="start",
|
|
stream_id=str(verona.id),
|
|
topic=Message.EMPTY_TOPIC_FALLBACK_NAME,
|
|
)
|
|
self.api_post(hamlet, "/api/v1/typing", params)
|
|
events = client.event_queue.contents()
|
|
self.assertEqual(events[8]["topic"], "")
|
|
self.assertEqual(events[9]["topic"], "")
|
|
|
|
# Prep to mark it as read before marking it as unread.
|
|
params = {
|
|
"messages": orjson.dumps([message_id, message_id_2]).decode(),
|
|
"op": "add",
|
|
"flag": "read",
|
|
}
|
|
self.client_post("/json/messages/flags", params)
|
|
|
|
with self.captureOnCommitCallbacks(execute=True):
|
|
params = {
|
|
"messages": orjson.dumps([message_id, message_id_2]).decode(),
|
|
"op": "remove",
|
|
"flag": "read",
|
|
}
|
|
self.client_post("/json/messages/flags", params)
|
|
events = client.event_queue.contents()
|
|
self.assertEqual(events[10]["message_details"][str(message_id)]["topic"], "")
|
|
self.assertEqual(events[10]["message_details"][str(message_id_2)]["topic"], "")
|
|
|
|
def test_client_not_supports_empty_topic_name(self) -> None:
|
|
iago = self.example_user("iago")
|
|
hamlet = self.example_user("hamlet")
|
|
queue_data = dict(
|
|
all_public_streams=True,
|
|
apply_markdown=True,
|
|
client_type_name="zulip-mobile",
|
|
empty_topic_name=False,
|
|
event_types=[
|
|
"message",
|
|
"update_message",
|
|
"delete_message",
|
|
"user_topic",
|
|
"typing",
|
|
"update_message_flags",
|
|
],
|
|
last_connection_time=time.time(),
|
|
queue_timeout=600,
|
|
realm_id=hamlet.realm.id,
|
|
stream_typing_notifications=True,
|
|
user_profile_id=hamlet.id,
|
|
)
|
|
client = allocate_client_descriptor(queue_data)
|
|
self.assertTrue(client.event_queue.empty())
|
|
|
|
message_id = self.send_stream_message(iago, "Denmark", topic_name="")
|
|
events = client.event_queue.contents()
|
|
self.assertEqual(events[0]["message"]["subject"], Message.EMPTY_TOPIC_FALLBACK_NAME)
|
|
|
|
message_id_2 = self.send_stream_message(
|
|
iago, "Denmark", topic_name=Message.EMPTY_TOPIC_FALLBACK_NAME
|
|
)
|
|
events = client.event_queue.contents()
|
|
self.assertEqual(events[1]["message"]["subject"], Message.EMPTY_TOPIC_FALLBACK_NAME)
|
|
|
|
self.login_user(iago)
|
|
with self.captureOnCommitCallbacks(execute=True):
|
|
params = {"topic": "new topic name", "send_notification_to_new_thread": "false"}
|
|
self.client_patch(f"/json/messages/{message_id}", params)
|
|
self.client_patch(f"/json/messages/{message_id_2}", params)
|
|
events = client.event_queue.contents()
|
|
self.assertEqual(events[2]["orig_subject"], Message.EMPTY_TOPIC_FALLBACK_NAME)
|
|
self.assertEqual(events[3]["orig_subject"], Message.EMPTY_TOPIC_FALLBACK_NAME)
|
|
|
|
# reset
|
|
message_id = self.send_stream_message(
|
|
iago, "Denmark", topic_name="", skip_capture_on_commit_callbacks=True
|
|
)
|
|
message_id_2 = self.send_stream_message(
|
|
iago,
|
|
"Verona",
|
|
topic_name=Message.EMPTY_TOPIC_FALLBACK_NAME,
|
|
skip_capture_on_commit_callbacks=True,
|
|
)
|
|
|
|
with self.captureOnCommitCallbacks(execute=True):
|
|
self.client_delete(f"/json/messages/{message_id}")
|
|
self.client_delete(f"/json/messages/{message_id_2}")
|
|
events = client.event_queue.contents()
|
|
self.assertEqual(events[4]["topic"], Message.EMPTY_TOPIC_FALLBACK_NAME)
|
|
self.assertEqual(events[5]["topic"], Message.EMPTY_TOPIC_FALLBACK_NAME)
|
|
|
|
# reset
|
|
message_id = self.send_stream_message(
|
|
iago, "Denmark", topic_name="", skip_capture_on_commit_callbacks=True
|
|
)
|
|
message_id_2 = self.send_stream_message(
|
|
iago,
|
|
"Verona",
|
|
topic_name=Message.EMPTY_TOPIC_FALLBACK_NAME,
|
|
skip_capture_on_commit_callbacks=True,
|
|
)
|
|
|
|
self.login_user(hamlet)
|
|
denmark = get_stream("Denmark", hamlet.realm)
|
|
verona = get_stream("Verona", hamlet.realm)
|
|
with self.captureOnCommitCallbacks(execute=True):
|
|
do_set_user_topic_visibility_policy(
|
|
hamlet,
|
|
denmark,
|
|
"",
|
|
visibility_policy=UserTopic.VisibilityPolicy.FOLLOWED,
|
|
)
|
|
do_set_user_topic_visibility_policy(
|
|
hamlet,
|
|
verona,
|
|
Message.EMPTY_TOPIC_FALLBACK_NAME,
|
|
visibility_policy=UserTopic.VisibilityPolicy.FOLLOWED,
|
|
)
|
|
events = client.event_queue.contents()
|
|
self.assertEqual(events[6]["topic_name"], Message.EMPTY_TOPIC_FALLBACK_NAME)
|
|
self.assertEqual(events[7]["topic_name"], Message.EMPTY_TOPIC_FALLBACK_NAME)
|
|
|
|
params = dict(
|
|
type="stream",
|
|
op="start",
|
|
stream_id=str(denmark.id),
|
|
topic="",
|
|
)
|
|
self.api_post(hamlet, "/api/v1/typing", params)
|
|
params = dict(
|
|
type="stream",
|
|
op="start",
|
|
stream_id=str(verona.id),
|
|
topic=Message.EMPTY_TOPIC_FALLBACK_NAME,
|
|
)
|
|
self.api_post(hamlet, "/api/v1/typing", params)
|
|
events = client.event_queue.contents()
|
|
self.assertEqual(events[8]["topic"], Message.EMPTY_TOPIC_FALLBACK_NAME)
|
|
self.assertEqual(events[9]["topic"], Message.EMPTY_TOPIC_FALLBACK_NAME)
|
|
|
|
# Prep to mark it as read before marking it as unread.
|
|
params = {
|
|
"messages": orjson.dumps([message_id, message_id_2]).decode(),
|
|
"op": "add",
|
|
"flag": "read",
|
|
}
|
|
self.client_post("/json/messages/flags", params)
|
|
|
|
with self.captureOnCommitCallbacks(execute=True):
|
|
params = {
|
|
"messages": orjson.dumps([message_id, message_id_2]).decode(),
|
|
"op": "remove",
|
|
"flag": "read",
|
|
}
|
|
self.client_post("/json/messages/flags", params)
|
|
events = client.event_queue.contents()
|
|
self.assertEqual(
|
|
events[10]["message_details"][str(message_id)]["topic"],
|
|
Message.EMPTY_TOPIC_FALLBACK_NAME,
|
|
)
|
|
self.assertEqual(
|
|
events[10]["message_details"][str(message_id_2)]["topic"],
|
|
Message.EMPTY_TOPIC_FALLBACK_NAME,
|
|
)
|
|
|
|
def test_fetch_messages(self) -> None:
|
|
hamlet = self.example_user("hamlet")
|
|
self.login_user(hamlet)
|
|
|
|
first_message_id = self.send_stream_message(hamlet, "Denmark", topic_name="")
|
|
second_message_id = self.send_stream_message(
|
|
hamlet, "Denmark", topic_name=Message.EMPTY_TOPIC_FALLBACK_NAME
|
|
)
|
|
|
|
# Fetch using `/messages` endpoint.
|
|
params = {
|
|
"allow_empty_topic_name": "false",
|
|
"message_ids": orjson.dumps([first_message_id, second_message_id]).decode(),
|
|
}
|
|
result = self.client_get("/json/messages", params)
|
|
data = self.assert_json_success(result)
|
|
self.assert_length(data["messages"], 2)
|
|
for message in data["messages"]:
|
|
self.assertEqual(message["subject"], Message.EMPTY_TOPIC_FALLBACK_NAME)
|
|
|
|
params = {
|
|
"allow_empty_topic_name": "true",
|
|
"message_ids": orjson.dumps([first_message_id, second_message_id]).decode(),
|
|
}
|
|
result = self.client_get("/json/messages", params)
|
|
data = self.assert_json_success(result)
|
|
self.assert_length(data["messages"], 2)
|
|
for message in data["messages"]:
|
|
self.assertEqual(message["subject"], "")
|
|
|
|
get_params = {
|
|
"allow_empty_topic_name": "false",
|
|
"anchor": "newest",
|
|
"num_before": 2,
|
|
"num_after": 0,
|
|
"narrow": orjson.dumps(
|
|
[
|
|
{"operator": "channel", "operand": "Denmark"},
|
|
{"operator": "topic", "operand": Message.EMPTY_TOPIC_FALLBACK_NAME},
|
|
]
|
|
).decode(),
|
|
}
|
|
result = self.client_get("/json/messages", get_params)
|
|
data = self.assert_json_success(result)
|
|
self.assert_length(data["messages"], 2)
|
|
for message in data["messages"]:
|
|
self.assertEqual(message["subject"], Message.EMPTY_TOPIC_FALLBACK_NAME)
|
|
|
|
# Fetch using `/messages/{message_id}` endpoint.
|
|
result = self.client_get(
|
|
f"/json/messages/{first_message_id}", {"allow_empty_topic_name": "false"}
|
|
)
|
|
data = self.assert_json_success(result)
|
|
self.assertEqual(data["message"]["subject"], Message.EMPTY_TOPIC_FALLBACK_NAME)
|
|
|
|
result = self.client_get(
|
|
f"/json/messages/{second_message_id}", {"allow_empty_topic_name": "false"}
|
|
)
|
|
data = self.assert_json_success(result)
|
|
self.assertEqual(data["message"]["subject"], Message.EMPTY_TOPIC_FALLBACK_NAME)
|
|
|
|
result = self.client_get(
|
|
f"/json/messages/{first_message_id}", {"allow_empty_topic_name": "true"}
|
|
)
|
|
data = self.assert_json_success(result)
|
|
self.assertEqual(data["message"]["subject"], "")
|
|
|
|
result = self.client_get(
|
|
f"/json/messages/{second_message_id}", {"allow_empty_topic_name": "true"}
|
|
)
|
|
data = self.assert_json_success(result)
|
|
self.assertEqual(data["message"]["subject"], "")
|
|
|
|
# Verify `edit_history` objects.
|
|
params = {"topic": "new topic name"}
|
|
result = self.client_patch(f"/json/messages/{first_message_id}", params)
|
|
self.assert_json_success(result)
|
|
|
|
result = self.client_get(
|
|
f"/json/messages/{first_message_id}", {"allow_empty_topic_name": "false"}
|
|
)
|
|
data = self.assert_json_success(result)
|
|
self.assertEqual(
|
|
data["message"]["edit_history"][0]["prev_topic"], Message.EMPTY_TOPIC_FALLBACK_NAME
|
|
)
|
|
|
|
result = self.client_get(
|
|
f"/json/messages/{first_message_id}", {"allow_empty_topic_name": "true"}
|
|
)
|
|
data = self.assert_json_success(result)
|
|
self.assertEqual(data["message"]["edit_history"][0]["prev_topic"], "")
|
|
|
|
params = {"topic": ""}
|
|
result = self.client_patch(f"/json/messages/{first_message_id}", params)
|
|
self.assert_json_success(result)
|
|
|
|
result = self.client_get(
|
|
f"/json/messages/{first_message_id}", {"allow_empty_topic_name": "false"}
|
|
)
|
|
data = self.assert_json_success(result)
|
|
self.assertEqual(
|
|
data["message"]["edit_history"][0]["topic"], Message.EMPTY_TOPIC_FALLBACK_NAME
|
|
)
|
|
|
|
result = self.client_get(
|
|
f"/json/messages/{first_message_id}", {"allow_empty_topic_name": "true"}
|
|
)
|
|
data = self.assert_json_success(result)
|
|
self.assertEqual(data["message"]["edit_history"][0]["topic"], "")
|
|
|
|
def test_get_message_edit_history(self) -> None:
|
|
hamlet = self.example_user("hamlet")
|
|
self.login_user(hamlet)
|
|
|
|
message_id = self.send_stream_message(hamlet, "Denmark", topic_name="")
|
|
message_id_2 = self.send_stream_message(
|
|
hamlet, "Denmark", topic_name=Message.EMPTY_TOPIC_FALLBACK_NAME
|
|
)
|
|
|
|
params = {"topic": "new topic name"}
|
|
result = self.client_patch(f"/json/messages/{message_id}", params)
|
|
self.assert_json_success(result)
|
|
result = self.client_patch(f"/json/messages/{message_id_2}", params)
|
|
self.assert_json_success(result)
|
|
|
|
params = {"allow_empty_topic_name": "false"}
|
|
result = self.client_get(f"/json/messages/{message_id}/history", params)
|
|
data = self.assert_json_success(result)
|
|
self.assertEqual(data["message_history"][0]["topic"], Message.EMPTY_TOPIC_FALLBACK_NAME)
|
|
self.assertEqual(
|
|
data["message_history"][1]["prev_topic"], Message.EMPTY_TOPIC_FALLBACK_NAME
|
|
)
|
|
|
|
result = self.client_get(f"/json/messages/{message_id_2}/history", params)
|
|
data = self.assert_json_success(result)
|
|
self.assertEqual(data["message_history"][0]["topic"], Message.EMPTY_TOPIC_FALLBACK_NAME)
|
|
self.assertEqual(
|
|
data["message_history"][1]["prev_topic"], Message.EMPTY_TOPIC_FALLBACK_NAME
|
|
)
|
|
|
|
params = {"allow_empty_topic_name": "true"}
|
|
result = self.client_get(f"/json/messages/{message_id}/history", params)
|
|
data = self.assert_json_success(result)
|
|
self.assertEqual(data["message_history"][0]["topic"], "")
|
|
self.assertEqual(data["message_history"][1]["prev_topic"], "")
|
|
|
|
result = self.client_get(f"/json/messages/{message_id_2}/history", params)
|
|
data = self.assert_json_success(result)
|
|
self.assertEqual(data["message_history"][0]["topic"], "")
|
|
self.assertEqual(data["message_history"][1]["prev_topic"], "")
|
|
|
|
def test_initial_state_data(self) -> None:
|
|
hamlet = self.example_user("hamlet")
|
|
iago = self.example_user("iago")
|
|
self.login_user(hamlet)
|
|
|
|
self.send_stream_message(hamlet, "Denmark", topic_name="")
|
|
self.send_stream_message(hamlet, "Verona", topic_name=Message.EMPTY_TOPIC_FALLBACK_NAME)
|
|
|
|
do_set_user_topic_visibility_policy(
|
|
iago,
|
|
get_stream("Denmark", iago.realm),
|
|
"",
|
|
visibility_policy=UserTopic.VisibilityPolicy.FOLLOWED,
|
|
)
|
|
do_set_user_topic_visibility_policy(
|
|
iago,
|
|
get_stream("Verona", iago.realm),
|
|
Message.EMPTY_TOPIC_FALLBACK_NAME,
|
|
visibility_policy=UserTopic.VisibilityPolicy.UNMUTED,
|
|
)
|
|
|
|
with mock.patch("zerver.lib.events.request_event_queue", return_value=1):
|
|
state_data = do_events_register(
|
|
iago,
|
|
iago.realm,
|
|
get_client("website"),
|
|
client_capabilities=ClientCapabilities(
|
|
empty_topic_name=True, notification_settings_null=False
|
|
),
|
|
fetch_event_types=["update_message_flags", "message", "user_topic"],
|
|
)
|
|
self.assertEqual(state_data["unread_msgs"]["streams"][0]["topic"], "")
|
|
self.assertEqual(state_data["unread_msgs"]["streams"][1]["topic"], "")
|
|
self.assertEqual(state_data["user_topics"][0]["topic_name"], "")
|
|
self.assertEqual(state_data["user_topics"][1]["topic_name"], "")
|
|
|
|
with mock.patch("zerver.lib.events.request_event_queue", return_value=1):
|
|
state_data = do_events_register(
|
|
iago,
|
|
iago.realm,
|
|
get_client("website"),
|
|
client_capabilities=ClientCapabilities(
|
|
empty_topic_name=False, notification_settings_null=False
|
|
),
|
|
fetch_event_types=["update_message_flags", "message", "user_topic"],
|
|
)
|
|
self.assertEqual(
|
|
state_data["unread_msgs"]["streams"][0]["topic"], Message.EMPTY_TOPIC_FALLBACK_NAME
|
|
)
|
|
self.assertEqual(
|
|
state_data["unread_msgs"]["streams"][1]["topic"], Message.EMPTY_TOPIC_FALLBACK_NAME
|
|
)
|
|
self.assertEqual(
|
|
state_data["user_topics"][0]["topic_name"], Message.EMPTY_TOPIC_FALLBACK_NAME
|
|
)
|
|
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"], "")
|