2020-07-04 16:00:43 +02:00
|
|
|
from django.utils.timezone import now as timezone_now
|
|
|
|
|
2022-04-14 23:51:16 +02:00
|
|
|
from zerver.actions.streams import do_change_stream_permission
|
2020-07-04 16:00:43 +02:00
|
|
|
from zerver.lib.test_classes import ZulipTestCase
|
2021-07-16 22:11:10 +02:00
|
|
|
from zerver.models import Message, UserMessage, get_client, get_realm, get_stream
|
2020-07-04 16:00:43 +02:00
|
|
|
|
|
|
|
|
|
|
|
class TopicHistoryTest(ZulipTestCase):
|
|
|
|
def test_topics_history_zephyr_mirror(self) -> None:
|
2021-02-12 08:20:45 +01:00
|
|
|
user_profile = self.mit_user("sipbtest")
|
|
|
|
stream_name = "new_stream"
|
2020-07-04 16:00:43 +02:00
|
|
|
|
|
|
|
# Send a message to this new stream from another user
|
|
|
|
self.subscribe(self.mit_user("starnine"), stream_name)
|
|
|
|
stream = get_stream(stream_name, user_profile.realm)
|
2021-02-12 08:19:30 +01:00
|
|
|
self.send_stream_message(self.mit_user("starnine"), stream_name, topic_name="secret topic")
|
2020-07-04 16:00:43 +02:00
|
|
|
|
|
|
|
# Now subscribe this MIT user to the new stream and verify
|
|
|
|
# that the new topic is not accessible
|
|
|
|
self.login_user(user_profile)
|
|
|
|
self.subscribe(user_profile, stream_name)
|
2021-02-12 08:20:45 +01:00
|
|
|
endpoint = f"/json/users/me/{stream.id}/topics"
|
2020-09-02 08:14:51 +02:00
|
|
|
result = self.client_get(endpoint, {}, subdomain="zephyr")
|
2022-06-07 01:37:01 +02:00
|
|
|
history = self.assert_json_success(result)["topics"]
|
2020-07-04 16:00:43 +02:00
|
|
|
self.assertEqual(history, [])
|
|
|
|
|
|
|
|
def test_topics_history(self) -> None:
|
|
|
|
# verified: int(UserMessage.flags.read) == 1
|
2021-02-12 08:20:45 +01:00
|
|
|
user_profile = self.example_user("iago")
|
2020-07-04 16:00:43 +02:00
|
|
|
self.login_user(user_profile)
|
2021-02-12 08:20:45 +01:00
|
|
|
stream_name = "Verona"
|
2020-07-04 16:00:43 +02:00
|
|
|
|
|
|
|
stream = get_stream(stream_name, user_profile.realm)
|
|
|
|
recipient = stream.recipient
|
|
|
|
|
|
|
|
def create_test_message(topic: str) -> int:
|
|
|
|
# TODO: Clean this up to send messages the normal way.
|
|
|
|
|
2021-02-12 08:20:45 +01:00
|
|
|
hamlet = self.example_user("hamlet")
|
2020-07-04 16:00:43 +02:00
|
|
|
message = Message(
|
|
|
|
sender=hamlet,
|
|
|
|
recipient=recipient,
|
2021-02-12 08:20:45 +01:00
|
|
|
content="whatever",
|
2020-07-04 16:00:43 +02:00
|
|
|
date_sent=timezone_now(),
|
2021-02-12 08:20:45 +01:00
|
|
|
sending_client=get_client("whatever"),
|
2020-07-04 16:00:43 +02:00
|
|
|
)
|
|
|
|
message.set_topic_name(topic)
|
|
|
|
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.
|
2021-02-12 08:20:45 +01:00
|
|
|
create_test_message("topic2")
|
|
|
|
create_test_message("toPIc1")
|
|
|
|
create_test_message("toPIc0")
|
|
|
|
create_test_message("topic2")
|
|
|
|
create_test_message("topic2")
|
|
|
|
create_test_message("Topic2")
|
2020-07-04 16:00:43 +02:00
|
|
|
|
|
|
|
# Create new messages
|
2021-02-12 08:20:45 +01:00
|
|
|
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")
|
2020-07-04 16:00:43 +02:00
|
|
|
|
2021-02-12 08:20:45 +01:00
|
|
|
endpoint = f"/json/users/me/{stream.id}/topics"
|
2020-09-02 08:14:51 +02:00
|
|
|
result = self.client_get(endpoint, {})
|
2022-06-07 01:37:01 +02:00
|
|
|
history = self.assert_json_success(result)["topics"]
|
2020-07-04 16:00:43 +02:00
|
|
|
|
|
|
|
# We only look at the most recent three topics, because
|
|
|
|
# the prior fixture data may be unreliable.
|
|
|
|
history = history[:3]
|
|
|
|
|
2021-02-12 08:19:30 +01:00
|
|
|
self.assertEqual(
|
2021-02-12 08:20:45 +01:00
|
|
|
[topic["name"] for topic in history],
|
2021-02-12 08:19:30 +01:00
|
|
|
[
|
2021-02-12 08:20:45 +01:00
|
|
|
"topic0",
|
|
|
|
"topic1",
|
|
|
|
"topic2",
|
2021-02-12 08:19:30 +01:00
|
|
|
],
|
|
|
|
)
|
2020-07-04 16:00:43 +02:00
|
|
|
|
2021-02-12 08:19:30 +01:00
|
|
|
self.assertEqual(
|
2021-02-12 08:20:45 +01:00
|
|
|
[topic["max_id"] for topic in history],
|
2021-02-12 08:19:30 +01:00
|
|
|
[
|
|
|
|
topic0_msg_id,
|
|
|
|
topic1_msg_id,
|
|
|
|
topic2_msg_id,
|
|
|
|
],
|
|
|
|
)
|
2020-07-04 16:00:43 +02:00
|
|
|
|
|
|
|
# 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.
|
2021-02-12 08:20:45 +01:00
|
|
|
self.login("cordelia")
|
2020-09-02 08:14:51 +02:00
|
|
|
result = self.client_get(endpoint, {})
|
2022-06-07 01:37:01 +02:00
|
|
|
history = self.assert_json_success(result)["topics"]
|
2020-07-04 16:00:43 +02:00
|
|
|
|
|
|
|
# We only look at the most recent three topics, because
|
|
|
|
# the prior fixture data may be unreliable.
|
|
|
|
history = history[:3]
|
|
|
|
|
2021-02-12 08:19:30 +01:00
|
|
|
self.assertEqual(
|
2021-02-12 08:20:45 +01:00
|
|
|
[topic["name"] for topic in history],
|
2021-02-12 08:19:30 +01:00
|
|
|
[
|
2021-02-12 08:20:45 +01:00
|
|
|
"topic0",
|
|
|
|
"topic1",
|
|
|
|
"topic2",
|
2021-02-12 08:19:30 +01:00
|
|
|
],
|
|
|
|
)
|
2021-02-12 08:20:45 +01:00
|
|
|
self.assertIn("topic0", [topic["name"] for topic in history])
|
2020-07-04 16:00:43 +02:00
|
|
|
|
2021-02-12 08:19:30 +01:00
|
|
|
self.assertEqual(
|
2021-02-12 08:20:45 +01:00
|
|
|
[topic["max_id"] for topic in history],
|
2021-02-12 08:19:30 +01:00
|
|
|
[
|
|
|
|
topic0_msg_id,
|
|
|
|
topic1_msg_id,
|
|
|
|
topic2_msg_id,
|
|
|
|
],
|
|
|
|
)
|
2020-07-04 16:00:43 +02:00
|
|
|
|
|
|
|
# Now make stream private, but subscribe cordelia
|
2021-12-11 00:41:25 +01:00
|
|
|
do_change_stream_permission(
|
2022-08-01 12:54:46 +02:00
|
|
|
stream,
|
|
|
|
invite_only=True,
|
|
|
|
history_public_to_subscribers=False,
|
|
|
|
is_web_public=False,
|
|
|
|
acting_user=self.example_user("cordelia"),
|
2021-12-11 00:41:25 +01:00
|
|
|
)
|
2020-07-04 16:00:43 +02:00
|
|
|
self.subscribe(self.example_user("cordelia"), stream.name)
|
|
|
|
|
2020-09-02 08:14:51 +02:00
|
|
|
result = self.client_get(endpoint, {})
|
2022-06-07 01:37:01 +02:00
|
|
|
history = self.assert_json_success(result)["topics"]
|
2020-07-04 16:00:43 +02:00
|
|
|
history = history[:3]
|
|
|
|
|
|
|
|
# Cordelia doesn't have these recent history items when we
|
|
|
|
# wasn't subscribed in her results.
|
2021-02-12 08:20:45 +01:00
|
|
|
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])
|
2020-07-04 16:00:43 +02:00
|
|
|
|
|
|
|
def test_bad_stream_id(self) -> None:
|
2021-02-12 08:20:45 +01:00
|
|
|
self.login("iago")
|
2020-07-04 16:00:43 +02:00
|
|
|
|
|
|
|
# non-sensible stream id
|
2021-02-12 08:20:45 +01:00
|
|
|
endpoint = "/json/users/me/9999999999/topics"
|
2020-09-02 08:14:51 +02:00
|
|
|
result = self.client_get(endpoint, {})
|
2022-05-27 14:03:08 +02:00
|
|
|
self.assert_json_error(result, "Invalid stream ID")
|
2020-07-04 16:00:43 +02:00
|
|
|
|
|
|
|
# out of realm
|
|
|
|
bad_stream = self.make_stream(
|
2021-02-12 08:20:45 +01:00
|
|
|
"mit_stream",
|
|
|
|
realm=get_realm("zephyr"),
|
2020-07-04 16:00:43 +02:00
|
|
|
)
|
2021-02-12 08:20:45 +01:00
|
|
|
endpoint = f"/json/users/me/{bad_stream.id}/topics"
|
2020-09-02 08:14:51 +02:00
|
|
|
result = self.client_get(endpoint, {})
|
2022-05-27 14:03:08 +02:00
|
|
|
self.assert_json_error(result, "Invalid stream ID")
|
2020-07-04 16:00:43 +02:00
|
|
|
|
|
|
|
# private stream to which I am not subscribed
|
|
|
|
private_stream = self.make_stream(
|
2021-02-12 08:20:45 +01:00
|
|
|
"private_stream",
|
2020-07-04 16:00:43 +02:00
|
|
|
invite_only=True,
|
|
|
|
)
|
2021-02-12 08:20:45 +01:00
|
|
|
endpoint = f"/json/users/me/{private_stream.id}/topics"
|
2020-09-02 08:14:51 +02:00
|
|
|
result = self.client_get(endpoint, {})
|
2022-05-27 14:03:08 +02:00
|
|
|
self.assert_json_error(result, "Invalid stream ID")
|
2020-07-04 16:00:43 +02:00
|
|
|
|
2020-08-21 17:12:05 +02:00
|
|
|
def test_get_topics_web_public_stream_web_public_request(self) -> None:
|
tests: Ensure stream senders get a UserMessage row.
We now complain if a test author sends a stream message
that does not result in the sender getting a
UserMessage row for the message.
This is basically 100% equivalent to complaining that
the author failed to subscribe the sender to the stream
as part of the test setup, as far as I can tell, so the
AssertionError instructs the author to subscribe the
sender to the stream.
We exempt bots from this check, although it is
plausible we should only exempt the system bots like
the notification bot.
I considered auto-subscribing the sender to the stream,
but that can be a little more expensive than the
current check, and we generally want test setup to be
explicit.
If there is some legitimate way than a subscribed human
sender can't get a UserMessage, then we probably want
an explicit test for that, or we may want to change the
backend to just write a UserMessage row in that
hypothetical situation.
For most tests, including almost all the ones fixed
here, the author just wants their test setup to
realistically reflect normal operation, and often devs
may not realize that Cordelia is not subscribed to
Denmark or not realize that Hamlet is not subscribed to
Scotland.
Some of us don't remember our Shakespeare from high
school, and our stream subscriptions don't even
necessarily reflect which countries the Bard placed his
characters in.
There may also be some legitimate use case where an
author wants to simulate sending a message to an
unsubscribed stream, but for those edge cases, they can
always set allow_unsubscribed_sender to True.
2021-12-10 13:55:48 +01:00
|
|
|
iago = self.example_user("iago")
|
2022-02-08 00:13:33 +01:00
|
|
|
stream = self.make_stream("web-public-stream", is_web_public=True)
|
tests: Ensure stream senders get a UserMessage row.
We now complain if a test author sends a stream message
that does not result in the sender getting a
UserMessage row for the message.
This is basically 100% equivalent to complaining that
the author failed to subscribe the sender to the stream
as part of the test setup, as far as I can tell, so the
AssertionError instructs the author to subscribe the
sender to the stream.
We exempt bots from this check, although it is
plausible we should only exempt the system bots like
the notification bot.
I considered auto-subscribing the sender to the stream,
but that can be a little more expensive than the
current check, and we generally want test setup to be
explicit.
If there is some legitimate way than a subscribed human
sender can't get a UserMessage, then we probably want
an explicit test for that, or we may want to change the
backend to just write a UserMessage row in that
hypothetical situation.
For most tests, including almost all the ones fixed
here, the author just wants their test setup to
realistically reflect normal operation, and often devs
may not realize that Cordelia is not subscribed to
Denmark or not realize that Hamlet is not subscribed to
Scotland.
Some of us don't remember our Shakespeare from high
school, and our stream subscriptions don't even
necessarily reflect which countries the Bard placed his
characters in.
There may also be some legitimate use case where an
author wants to simulate sending a message to an
unsubscribed stream, but for those edge cases, they can
always set allow_unsubscribed_sender to True.
2021-12-10 13:55:48 +01:00
|
|
|
self.subscribe(iago, stream.name)
|
|
|
|
|
2020-08-21 17:12:05 +02:00
|
|
|
for i in range(3):
|
tests: Ensure stream senders get a UserMessage row.
We now complain if a test author sends a stream message
that does not result in the sender getting a
UserMessage row for the message.
This is basically 100% equivalent to complaining that
the author failed to subscribe the sender to the stream
as part of the test setup, as far as I can tell, so the
AssertionError instructs the author to subscribe the
sender to the stream.
We exempt bots from this check, although it is
plausible we should only exempt the system bots like
the notification bot.
I considered auto-subscribing the sender to the stream,
but that can be a little more expensive than the
current check, and we generally want test setup to be
explicit.
If there is some legitimate way than a subscribed human
sender can't get a UserMessage, then we probably want
an explicit test for that, or we may want to change the
backend to just write a UserMessage row in that
hypothetical situation.
For most tests, including almost all the ones fixed
here, the author just wants their test setup to
realistically reflect normal operation, and often devs
may not realize that Cordelia is not subscribed to
Denmark or not realize that Hamlet is not subscribed to
Scotland.
Some of us don't remember our Shakespeare from high
school, and our stream subscriptions don't even
necessarily reflect which countries the Bard placed his
characters in.
There may also be some legitimate use case where an
author wants to simulate sending a message to an
unsubscribed stream, but for those edge cases, they can
always set allow_unsubscribed_sender to True.
2021-12-10 13:55:48 +01:00
|
|
|
self.send_stream_message(iago, stream.name, topic_name="topic" + str(i))
|
2020-08-21 17:12:05 +02:00
|
|
|
|
2021-02-12 08:20:45 +01:00
|
|
|
endpoint = f"/json/users/me/{stream.id}/topics"
|
2020-08-21 17:12:05 +02:00
|
|
|
result = self.client_get(endpoint)
|
2022-06-07 01:37:01 +02:00
|
|
|
history = self.assert_json_success(result)["topics"]
|
2021-02-12 08:19:30 +01:00
|
|
|
self.assertEqual(
|
2021-02-12 08:20:45 +01:00
|
|
|
[topic["name"] for topic in history],
|
2021-02-12 08:19:30 +01:00
|
|
|
[
|
2021-02-12 08:20:45 +01:00
|
|
|
"topic2",
|
|
|
|
"topic1",
|
|
|
|
"topic0",
|
2021-02-12 08:19:30 +01:00
|
|
|
],
|
|
|
|
)
|
2020-08-21 17:12:05 +02:00
|
|
|
|
|
|
|
def test_get_topics_non_web_public_stream_web_public_request(self) -> None:
|
2021-02-12 08:20:45 +01:00
|
|
|
stream = get_stream("Verona", self.example_user("iago").realm)
|
|
|
|
endpoint = f"/json/users/me/{stream.id}/topics"
|
2020-08-21 17:12:05 +02:00
|
|
|
result = self.client_get(endpoint)
|
2022-05-27 14:03:08 +02:00
|
|
|
self.assert_json_error(result, "Invalid stream ID", 400)
|
2020-08-21 17:12:05 +02:00
|
|
|
|
2022-02-08 00:13:33 +01:00
|
|
|
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"
|
2020-08-21 17:12:05 +02:00
|
|
|
result = self.client_get(endpoint)
|
2022-05-27 14:03:08 +02:00
|
|
|
self.assert_json_error(result, "Invalid stream ID", 400)
|
2020-08-21 17:12:05 +02:00
|
|
|
|
2021-02-12 08:19:30 +01:00
|
|
|
|
2020-07-04 16:00:43 +02:00
|
|
|
class TopicDeleteTest(ZulipTestCase):
|
|
|
|
def test_topic_delete(self) -> None:
|
|
|
|
initial_last_msg_id = self.get_last_message().id
|
2021-02-12 08:20:45 +01:00
|
|
|
stream_name = "new_stream"
|
|
|
|
topic_name = "new topic 2"
|
2020-07-04 16:00:43 +02:00
|
|
|
|
|
|
|
# NON-ADMIN USER
|
2021-02-12 08:20:45 +01:00
|
|
|
user_profile = self.example_user("hamlet")
|
2020-07-04 16:00:43 +02:00
|
|
|
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)
|
2021-02-12 08:20:45 +01:00
|
|
|
endpoint = "/json/streams/" + str(stream.id) + "/delete_topic"
|
2021-02-12 08:19:30 +01:00
|
|
|
result = self.client_post(
|
|
|
|
endpoint,
|
|
|
|
{
|
|
|
|
"topic_name": topic_name,
|
|
|
|
},
|
|
|
|
)
|
2020-07-04 16:00:43 +02:00
|
|
|
self.assert_json_error(result, "Must be an organization administrator")
|
2021-12-11 00:41:25 +01:00
|
|
|
self.assertTrue(Message.objects.filter(id=last_msg_id).exists())
|
2020-07-04 16:00:43 +02:00
|
|
|
|
|
|
|
# Make stream private with limited history
|
2021-12-11 00:41:25 +01:00
|
|
|
do_change_stream_permission(
|
2022-08-01 12:54:46 +02:00
|
|
|
stream,
|
|
|
|
invite_only=True,
|
|
|
|
history_public_to_subscribers=False,
|
|
|
|
is_web_public=False,
|
|
|
|
acting_user=user_profile,
|
2021-12-11 00:41:25 +01:00
|
|
|
)
|
2020-07-04 16:00:43 +02:00
|
|
|
|
|
|
|
# ADMIN USER subscribed now
|
2021-02-12 08:20:45 +01:00
|
|
|
user_profile = self.example_user("iago")
|
2020-07-04 16:00:43 +02:00
|
|
|
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)
|
|
|
|
|
|
|
|
# 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)
|
2021-02-12 08:19:30 +01:00
|
|
|
result = self.client_post(
|
|
|
|
endpoint,
|
|
|
|
{
|
|
|
|
"topic_name": topic_name,
|
|
|
|
},
|
|
|
|
)
|
2020-07-04 16:00:43 +02:00
|
|
|
self.assert_json_success(result)
|
2021-12-11 00:41:25 +01:00
|
|
|
self.assertTrue(Message.objects.filter(id=last_msg_id).exists())
|
2020-07-04 16:00:43 +02:00
|
|
|
|
|
|
|
# Try to delete all messages in the topic again. There are no messages accessible
|
|
|
|
# to the administrator, so this should do nothing.
|
2021-02-12 08:19:30 +01:00
|
|
|
result = self.client_post(
|
|
|
|
endpoint,
|
|
|
|
{
|
|
|
|
"topic_name": topic_name,
|
|
|
|
},
|
|
|
|
)
|
2020-07-04 16:00:43 +02:00
|
|
|
self.assert_json_success(result)
|
2021-12-11 00:41:25 +01:00
|
|
|
self.assertTrue(Message.objects.filter(id=last_msg_id).exists())
|
2020-07-04 16:00:43 +02:00
|
|
|
|
|
|
|
# Make the stream's history public to subscribers
|
2021-12-11 00:41:25 +01:00
|
|
|
do_change_stream_permission(
|
2022-08-01 12:54:46 +02:00
|
|
|
stream,
|
|
|
|
invite_only=True,
|
|
|
|
history_public_to_subscribers=True,
|
|
|
|
is_web_public=False,
|
|
|
|
acting_user=user_profile,
|
2021-12-11 00:41:25 +01:00
|
|
|
)
|
2020-07-04 16:00:43 +02:00
|
|
|
# Delete the topic should now remove all messages
|
2021-02-12 08:19:30 +01:00
|
|
|
result = self.client_post(
|
|
|
|
endpoint,
|
|
|
|
{
|
|
|
|
"topic_name": topic_name,
|
|
|
|
},
|
|
|
|
)
|
2020-07-04 16:00:43 +02:00
|
|
|
self.assert_json_success(result)
|
2021-12-11 00:41:25 +01:00
|
|
|
self.assertFalse(Message.objects.filter(id=last_msg_id).exists())
|
|
|
|
self.assertTrue(Message.objects.filter(id=initial_last_msg_id).exists())
|
2020-07-04 16:00:43 +02:00
|
|
|
|
|
|
|
# Delete again, to test the edge case of deleting an empty topic.
|
2021-02-12 08:19:30 +01:00
|
|
|
result = self.client_post(
|
|
|
|
endpoint,
|
|
|
|
{
|
|
|
|
"topic_name": topic_name,
|
|
|
|
},
|
|
|
|
)
|
2020-07-04 16:00:43 +02:00
|
|
|
self.assert_json_success(result)
|
2021-12-11 00:41:25 +01:00
|
|
|
self.assertFalse(Message.objects.filter(id=last_msg_id).exists())
|
|
|
|
self.assertTrue(Message.objects.filter(id=initial_last_msg_id).exists())
|