2020-08-07 01:09:47 +02:00
|
|
|
import orjson
|
2016-10-12 20:57:59 +02:00
|
|
|
|
2020-06-11 00:54:34 +02:00
|
|
|
from zerver.lib.test_classes import ZulipTestCase
|
2024-07-05 13:13:40 +02:00
|
|
|
from zerver.models import DirectMessageGroup
|
2024-07-04 14:05:48 +02:00
|
|
|
from zerver.models.recipients import get_direct_message_group_hash
|
2020-06-11 00:54:34 +02:00
|
|
|
|
2016-10-12 20:57:59 +02:00
|
|
|
|
2020-02-22 13:38:09 +01:00
|
|
|
class TypingValidateOperatorTest(ZulipTestCase):
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_missing_parameter(self) -> None:
|
2016-10-12 20:57:59 +02:00
|
|
|
"""
|
|
|
|
Sending typing notification without op parameter fails
|
|
|
|
"""
|
2020-02-22 13:38:09 +01:00
|
|
|
sender = self.example_user("hamlet")
|
|
|
|
params = dict(
|
2020-08-07 01:09:47 +02:00
|
|
|
to=orjson.dumps([sender.id]).decode(),
|
2020-02-22 13:38:09 +01:00
|
|
|
)
|
2021-02-12 08:20:45 +01:00
|
|
|
result = self.api_post(sender, "/api/v1/typing", params)
|
|
|
|
self.assert_json_error(result, "Missing 'op' argument")
|
2016-10-12 20:57:59 +02:00
|
|
|
|
2023-10-07 12:42:49 +02:00
|
|
|
def test_invalid_parameter_direct_message(self) -> None:
|
2016-10-12 20:57:59 +02:00
|
|
|
"""
|
|
|
|
Sending typing notification with invalid value for op parameter fails
|
|
|
|
"""
|
2020-02-22 13:38:09 +01:00
|
|
|
sender = self.example_user("hamlet")
|
|
|
|
params = dict(
|
2020-08-07 01:09:47 +02:00
|
|
|
to=orjson.dumps([sender.id]).decode(),
|
2021-02-12 08:20:45 +01:00
|
|
|
op="foo",
|
2020-02-22 13:38:09 +01:00
|
|
|
)
|
2021-02-12 08:20:45 +01:00
|
|
|
result = self.api_post(sender, "/api/v1/typing", params)
|
2021-02-05 19:32:46 +01:00
|
|
|
self.assert_json_error(result, "Invalid op")
|
2016-10-12 20:57:59 +02:00
|
|
|
|
2020-12-24 21:00:20 +01:00
|
|
|
def test_invalid_parameter_stream(self) -> None:
|
|
|
|
sender = self.example_user("hamlet")
|
|
|
|
|
|
|
|
result = self.api_post(
|
|
|
|
sender, "/api/v1/typing", {"op": "foo", "stream_id": 1, "topic": "topic"}
|
|
|
|
)
|
|
|
|
self.assert_json_error(result, "Invalid op")
|
|
|
|
|
2021-02-12 08:19:30 +01:00
|
|
|
|
2021-04-04 12:11:19 +02:00
|
|
|
class TypingMessagetypeTest(ZulipTestCase):
|
|
|
|
def test_invalid_type(self) -> None:
|
|
|
|
sender = self.example_user("hamlet")
|
|
|
|
params = dict(
|
|
|
|
to=orjson.dumps([sender.id]).decode(),
|
|
|
|
type="invalid",
|
|
|
|
op="start",
|
|
|
|
)
|
|
|
|
result = self.api_post(sender, "/api/v1/typing", params)
|
|
|
|
self.assert_json_error(result, "Invalid type")
|
|
|
|
|
|
|
|
|
2020-12-24 21:00:20 +01:00
|
|
|
class TypingValidateToArgumentsTest(ZulipTestCase):
|
2023-10-07 09:22:12 +02:00
|
|
|
def test_invalid_to_for_direct_messages(self) -> None:
|
2020-02-22 13:38:09 +01:00
|
|
|
"""
|
2023-10-07 09:22:12 +02:00
|
|
|
Sending dms typing notifications without 'to' as a list fails.
|
2020-02-22 13:38:09 +01:00
|
|
|
"""
|
2020-03-10 11:48:26 +01:00
|
|
|
sender = self.example_user("hamlet")
|
2023-10-07 09:22:12 +02:00
|
|
|
result = self.api_post(sender, "/api/v1/typing", {"op": "start", "to": "2"})
|
2023-10-12 09:13:34 +02:00
|
|
|
self.assert_json_error(result, "to is not a list")
|
2023-10-07 09:22:12 +02:00
|
|
|
|
|
|
|
def test_invalid_user_id_for_direct_messages(self) -> None:
|
|
|
|
"""
|
|
|
|
Sending dms typing notifications with invalid user_id fails.
|
|
|
|
"""
|
|
|
|
sender = self.example_user("hamlet")
|
|
|
|
invalid_user_ids = orjson.dumps([2, "a", 4]).decode()
|
|
|
|
result = self.api_post(sender, "/api/v1/typing", {"op": "start", "to": invalid_user_ids})
|
2023-10-12 09:13:34 +02:00
|
|
|
self.assert_json_error(result, "to[1] is not an integer")
|
2023-10-07 09:22:12 +02:00
|
|
|
|
|
|
|
def test_empty_to_array_direct_messages(self) -> None:
|
|
|
|
"""
|
|
|
|
Sending dms typing notification without recipient fails
|
|
|
|
"""
|
|
|
|
sender = self.example_user("hamlet")
|
|
|
|
result = self.api_post(sender, "/api/v1/typing", {"op": "start", "to": "[]"})
|
2020-12-24 21:00:20 +01:00
|
|
|
self.assert_json_error(result, "Empty 'to' list")
|
2020-02-22 13:38:09 +01:00
|
|
|
|
2017-11-05 10:51:25 +01:00
|
|
|
def test_missing_recipient(self) -> None:
|
2016-10-12 20:57:59 +02:00
|
|
|
"""
|
|
|
|
Sending typing notification without recipient fails
|
|
|
|
"""
|
2020-03-10 11:48:26 +01:00
|
|
|
sender = self.example_user("hamlet")
|
2021-02-12 08:20:45 +01:00
|
|
|
result = self.api_post(sender, "/api/v1/typing", {"op": "start"})
|
2020-02-28 18:23:57 +01:00
|
|
|
self.assert_json_error(result, "Missing 'to' argument")
|
2016-10-12 20:57:59 +02:00
|
|
|
|
2020-02-22 13:38:09 +01:00
|
|
|
def test_bogus_user_id(self) -> None:
|
2016-10-12 20:57:59 +02:00
|
|
|
"""
|
2020-02-22 13:38:09 +01:00
|
|
|
Sending typing notification to invalid recipient fails
|
2016-10-12 20:57:59 +02:00
|
|
|
"""
|
2020-03-10 11:48:26 +01:00
|
|
|
sender = self.example_user("hamlet")
|
2021-02-12 08:20:45 +01:00
|
|
|
invalid = "[9999999]"
|
|
|
|
result = self.api_post(sender, "/api/v1/typing", {"op": "start", "to": invalid})
|
|
|
|
self.assert_json_error(result, "Invalid user ID 9999999")
|
2016-10-12 20:57:59 +02:00
|
|
|
|
2023-10-12 09:13:34 +02:00
|
|
|
|
|
|
|
class TypingValidateStreamIdTopicArgumentsTest(ZulipTestCase):
|
|
|
|
def test_missing_stream_id(self) -> None:
|
|
|
|
"""
|
|
|
|
Sending stream typing notifications without 'stream_id' fails.
|
|
|
|
"""
|
|
|
|
sender = self.example_user("hamlet")
|
|
|
|
result = self.api_post(
|
|
|
|
sender,
|
|
|
|
"/api/v1/typing",
|
|
|
|
{"type": "stream", "op": "start", "topic": "test"},
|
|
|
|
)
|
2024-04-16 15:52:21 +02:00
|
|
|
self.assert_json_error(result, "Missing 'stream_id' argument")
|
2023-10-12 09:13:34 +02:00
|
|
|
|
|
|
|
def test_invalid_stream_id(self) -> None:
|
|
|
|
"""
|
|
|
|
Sending stream typing notifications without 'stream_id' as an integer fails.
|
|
|
|
"""
|
|
|
|
sender = self.example_user("hamlet")
|
|
|
|
result = self.api_post(
|
|
|
|
sender,
|
|
|
|
"/api/v1/typing",
|
|
|
|
{"type": "stream", "op": "start", "stream_id": "invalid", "topic": "test"},
|
|
|
|
)
|
2024-06-06 14:05:03 +02:00
|
|
|
self.assert_json_error(result, "stream_id is not valid JSON")
|
2023-10-12 09:13:34 +02:00
|
|
|
|
2020-12-24 21:00:20 +01:00
|
|
|
def test_includes_stream_id_but_not_topic(self) -> None:
|
|
|
|
sender = self.example_user("hamlet")
|
|
|
|
stream_id = self.get_stream_id("general")
|
|
|
|
|
|
|
|
result = self.api_post(
|
|
|
|
sender,
|
|
|
|
"/api/v1/typing",
|
2023-10-12 09:13:34 +02:00
|
|
|
{"type": "stream", "op": "start", "stream_id": str(stream_id)},
|
2020-12-24 21:00:20 +01:00
|
|
|
)
|
|
|
|
self.assert_json_error(result, "Missing topic")
|
|
|
|
|
|
|
|
def test_stream_doesnt_exist(self) -> None:
|
|
|
|
sender = self.example_user("hamlet")
|
|
|
|
stream_id = self.INVALID_STREAM_ID
|
2024-01-15 12:17:50 +01:00
|
|
|
topic_name = "some topic"
|
2020-12-24 21:00:20 +01:00
|
|
|
|
|
|
|
result = self.api_post(
|
|
|
|
sender,
|
|
|
|
"/api/v1/typing",
|
|
|
|
{
|
|
|
|
"type": "stream",
|
|
|
|
"op": "start",
|
2023-10-12 09:13:34 +02:00
|
|
|
"stream_id": str(stream_id),
|
2024-01-15 12:17:50 +01:00
|
|
|
"topic": topic_name,
|
2020-12-24 21:00:20 +01:00
|
|
|
},
|
|
|
|
)
|
2024-04-16 20:31:49 +02:00
|
|
|
self.assert_json_error(result, "Invalid channel ID")
|
2021-02-12 08:19:30 +01:00
|
|
|
|
2020-12-24 21:00:20 +01:00
|
|
|
|
2023-10-07 12:42:49 +02:00
|
|
|
class TypingHappyPathTestDirectMessages(ZulipTestCase):
|
2023-04-17 17:02:07 +02:00
|
|
|
def test_valid_type_and_op_parameters(self) -> None:
|
|
|
|
operator_type = ["start", "stop"]
|
|
|
|
sender = self.example_user("hamlet")
|
|
|
|
recipient_user = self.example_user("othello")
|
|
|
|
|
2023-10-01 20:59:21 +02:00
|
|
|
for operator in operator_type:
|
|
|
|
params = dict(
|
|
|
|
to=orjson.dumps([recipient_user.id]).decode(),
|
|
|
|
op=operator,
|
|
|
|
type="direct",
|
|
|
|
)
|
2023-04-17 17:02:07 +02:00
|
|
|
|
2023-10-01 20:59:21 +02:00
|
|
|
result = self.api_post(sender, "/api/v1/typing", params)
|
|
|
|
self.assert_json_success(result)
|
2023-04-17 17:02:07 +02:00
|
|
|
|
2020-02-22 13:38:09 +01:00
|
|
|
def test_start_to_single_recipient(self) -> None:
|
2021-02-12 08:20:45 +01:00
|
|
|
sender = self.example_user("hamlet")
|
|
|
|
recipient_user = self.example_user("othello")
|
2020-04-09 21:51:58 +02:00
|
|
|
expected_recipients = {sender, recipient_user}
|
|
|
|
expected_recipient_emails = {user.email for user in expected_recipients}
|
|
|
|
expected_recipient_ids = {user.id for user in expected_recipients}
|
2018-08-28 21:48:47 +02:00
|
|
|
|
2020-02-23 17:24:41 +01:00
|
|
|
params = dict(
|
2020-08-07 01:09:47 +02:00
|
|
|
to=orjson.dumps([recipient_user.id]).decode(),
|
2021-02-12 08:20:45 +01:00
|
|
|
op="start",
|
2020-02-23 17:24:41 +01:00
|
|
|
)
|
|
|
|
|
2022-10-15 22:47:40 +02:00
|
|
|
with self.assert_database_query_count(4):
|
2023-04-05 13:36:01 +02:00
|
|
|
with self.capture_send_event_calls(expected_num_events=1) as events:
|
2021-02-12 08:20:45 +01:00
|
|
|
result = self.api_post(sender, "/api/v1/typing", params)
|
2018-08-28 21:48:47 +02:00
|
|
|
|
|
|
|
self.assert_json_success(result)
|
2021-05-17 05:41:32 +02:00
|
|
|
self.assert_length(events, 1)
|
2018-08-28 21:48:47 +02:00
|
|
|
|
2021-02-12 08:20:45 +01:00
|
|
|
event = events[0]["event"]
|
|
|
|
event_recipient_emails = {user["email"] for user in event["recipients"]}
|
|
|
|
event_user_ids = set(events[0]["users"])
|
|
|
|
event_recipient_user_ids = {user["user_id"] for user in event["recipients"]}
|
2018-08-28 21:48:47 +02:00
|
|
|
|
|
|
|
self.assertEqual(expected_recipient_ids, event_recipient_user_ids)
|
|
|
|
self.assertEqual(expected_recipient_ids, event_user_ids)
|
2021-02-12 08:20:45 +01:00
|
|
|
self.assertEqual(event["sender"]["email"], sender.email)
|
2018-08-28 21:48:47 +02:00
|
|
|
self.assertEqual(event_recipient_emails, expected_recipient_emails)
|
2021-02-12 08:20:45 +01:00
|
|
|
self.assertEqual(event["type"], "typing")
|
|
|
|
self.assertEqual(event["op"], "start")
|
2018-08-28 21:48:47 +02:00
|
|
|
|
2020-02-22 13:38:09 +01:00
|
|
|
def test_start_to_multiple_recipients(self) -> None:
|
2021-02-12 08:20:45 +01:00
|
|
|
sender = self.example_user("hamlet")
|
|
|
|
recipient_users = [self.example_user("othello"), self.example_user("cordelia")]
|
2020-04-09 21:51:58 +02:00
|
|
|
expected_recipients = set(recipient_users) | {sender}
|
|
|
|
expected_recipient_emails = {user.email for user in expected_recipients}
|
|
|
|
expected_recipient_ids = {user.id for user in expected_recipients}
|
2020-02-23 18:05:29 +01:00
|
|
|
|
2024-07-04 14:05:48 +02:00
|
|
|
direct_message_group_hash = get_direct_message_group_hash(list(expected_recipient_ids))
|
2024-07-05 13:13:40 +02:00
|
|
|
self.assertFalse(
|
|
|
|
DirectMessageGroup.objects.filter(huddle_hash=direct_message_group_hash).exists()
|
|
|
|
)
|
2020-02-23 18:05:29 +01:00
|
|
|
|
2020-02-23 17:24:41 +01:00
|
|
|
params = dict(
|
2020-08-07 01:09:47 +02:00
|
|
|
to=orjson.dumps([user.id for user in recipient_users]).decode(),
|
2021-02-12 08:20:45 +01:00
|
|
|
op="start",
|
2020-02-23 17:24:41 +01:00
|
|
|
)
|
|
|
|
|
2022-10-15 22:47:40 +02:00
|
|
|
with self.assert_database_query_count(5):
|
2023-04-05 13:36:01 +02:00
|
|
|
with self.capture_send_event_calls(expected_num_events=1) as events:
|
2021-02-12 08:20:45 +01:00
|
|
|
result = self.api_post(sender, "/api/v1/typing", params)
|
2018-08-28 21:48:47 +02:00
|
|
|
self.assert_json_success(result)
|
2021-05-17 05:41:32 +02:00
|
|
|
self.assert_length(events, 1)
|
2018-08-28 21:48:47 +02:00
|
|
|
|
2024-07-04 14:05:48 +02:00
|
|
|
# We should not be adding new Direct Message groups
|
|
|
|
# just because a user started typing in the compose
|
|
|
|
# box. Let's wait till they send an actual message.
|
2024-07-05 13:13:40 +02:00
|
|
|
self.assertFalse(
|
|
|
|
DirectMessageGroup.objects.filter(huddle_hash=direct_message_group_hash).exists()
|
|
|
|
)
|
2020-02-23 18:05:29 +01:00
|
|
|
|
2021-02-12 08:20:45 +01:00
|
|
|
event = events[0]["event"]
|
|
|
|
event_recipient_emails = {user["email"] for user in event["recipients"]}
|
|
|
|
event_user_ids = set(events[0]["users"])
|
|
|
|
event_recipient_user_ids = {user["user_id"] for user in event["recipients"]}
|
2018-08-28 21:48:47 +02:00
|
|
|
|
|
|
|
self.assertEqual(expected_recipient_ids, event_recipient_user_ids)
|
|
|
|
self.assertEqual(expected_recipient_ids, event_user_ids)
|
2021-02-12 08:20:45 +01:00
|
|
|
self.assertEqual(event["sender"]["email"], sender.email)
|
2018-08-28 21:48:47 +02:00
|
|
|
self.assertEqual(event_recipient_emails, expected_recipient_emails)
|
2021-02-12 08:20:45 +01:00
|
|
|
self.assertEqual(event["type"], "typing")
|
|
|
|
self.assertEqual(event["op"], "start")
|
2018-08-28 21:48:47 +02:00
|
|
|
|
2020-02-22 13:38:09 +01:00
|
|
|
def test_start_to_self(self) -> None:
|
2018-08-28 21:48:47 +02:00
|
|
|
"""
|
|
|
|
Sending typing notification to yourself (using user IDs)
|
|
|
|
is successful.
|
|
|
|
"""
|
2021-02-12 08:20:45 +01:00
|
|
|
user = self.example_user("hamlet")
|
2018-08-28 21:48:47 +02:00
|
|
|
email = user.email
|
2020-04-09 21:51:58 +02:00
|
|
|
expected_recipient_emails = {email}
|
|
|
|
expected_recipient_ids = {user.id}
|
2023-04-05 13:36:01 +02:00
|
|
|
with self.capture_send_event_calls(expected_num_events=1) as events:
|
2018-08-28 21:48:47 +02:00
|
|
|
result = self.api_post(
|
2020-03-10 11:48:26 +01:00
|
|
|
user,
|
2021-02-12 08:20:45 +01:00
|
|
|
"/api/v1/typing",
|
2018-08-28 21:48:47 +02:00
|
|
|
{
|
2021-02-12 08:20:45 +01:00
|
|
|
"to": orjson.dumps([user.id]).decode(),
|
|
|
|
"op": "start",
|
python: Use trailing commas consistently.
Automatically generated by the following script, based on the output
of lint with flake8-comma:
import re
import sys
last_filename = None
last_row = None
lines = []
for msg in sys.stdin:
m = re.match(
r"\x1b\[35mflake8 \|\x1b\[0m \x1b\[1;31m(.+):(\d+):(\d+): (\w+)", msg
)
if m:
filename, row_str, col_str, err = m.groups()
row, col = int(row_str), int(col_str)
if filename == last_filename:
assert last_row != row
else:
if last_filename is not None:
with open(last_filename, "w") as f:
f.writelines(lines)
with open(filename) as f:
lines = f.readlines()
last_filename = filename
last_row = row
line = lines[row - 1]
if err in ["C812", "C815"]:
lines[row - 1] = line[: col - 1] + "," + line[col - 1 :]
elif err in ["C819"]:
assert line[col - 2] == ","
lines[row - 1] = line[: col - 2] + line[col - 1 :].lstrip(" ")
if last_filename is not None:
with open(last_filename, "w") as f:
f.writelines(lines)
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-04-10 05:23:40 +02:00
|
|
|
},
|
2018-08-28 21:48:47 +02:00
|
|
|
)
|
|
|
|
self.assert_json_success(result)
|
2021-05-17 05:41:32 +02:00
|
|
|
self.assert_length(events, 1)
|
2016-10-12 20:57:59 +02:00
|
|
|
|
2021-02-12 08:20:45 +01:00
|
|
|
event = events[0]["event"]
|
|
|
|
event_recipient_emails = {user["email"] for user in event["recipients"]}
|
|
|
|
event_user_ids = set(events[0]["users"])
|
|
|
|
event_recipient_user_ids = {user["user_id"] for user in event["recipients"]}
|
2016-10-12 20:57:59 +02:00
|
|
|
|
2016-10-28 18:50:21 +02:00
|
|
|
self.assertEqual(expected_recipient_ids, event_recipient_user_ids)
|
|
|
|
self.assertEqual(expected_recipient_ids, event_user_ids)
|
|
|
|
self.assertEqual(event_recipient_emails, expected_recipient_emails)
|
2021-02-12 08:20:45 +01:00
|
|
|
self.assertEqual(event["sender"]["email"], email)
|
|
|
|
self.assertEqual(event["type"], "typing")
|
|
|
|
self.assertEqual(event["op"], "start")
|
2016-10-12 20:57:59 +02:00
|
|
|
|
2020-02-22 13:38:09 +01:00
|
|
|
def test_start_to_another_user(self) -> None:
|
2016-10-12 20:57:59 +02:00
|
|
|
"""
|
|
|
|
Sending typing notification to another user
|
|
|
|
is successful.
|
|
|
|
"""
|
2021-02-12 08:20:45 +01:00
|
|
|
sender = self.example_user("hamlet")
|
|
|
|
recipient = self.example_user("othello")
|
2020-04-09 21:51:58 +02:00
|
|
|
expected_recipients = {sender, recipient}
|
|
|
|
expected_recipient_emails = {user.email for user in expected_recipients}
|
|
|
|
expected_recipient_ids = {user.id for user in expected_recipients}
|
2016-10-28 18:50:21 +02:00
|
|
|
|
2020-02-22 13:38:09 +01:00
|
|
|
params = dict(
|
2020-08-07 01:09:47 +02:00
|
|
|
to=orjson.dumps([recipient.id]).decode(),
|
2021-02-12 08:20:45 +01:00
|
|
|
op="start",
|
2020-02-22 13:38:09 +01:00
|
|
|
)
|
|
|
|
|
2023-04-05 13:36:01 +02:00
|
|
|
with self.capture_send_event_calls(expected_num_events=1) as events:
|
2021-02-12 08:20:45 +01:00
|
|
|
result = self.api_post(sender, "/api/v1/typing", params)
|
2020-02-22 13:38:09 +01:00
|
|
|
|
2016-10-12 20:57:59 +02:00
|
|
|
self.assert_json_success(result)
|
2021-05-17 05:41:32 +02:00
|
|
|
self.assert_length(events, 1)
|
2016-10-12 20:57:59 +02:00
|
|
|
|
2021-02-12 08:20:45 +01:00
|
|
|
event = events[0]["event"]
|
|
|
|
event_recipient_emails = {user["email"] for user in event["recipients"]}
|
|
|
|
event_user_ids = set(events[0]["users"])
|
|
|
|
event_recipient_user_ids = {user["user_id"] for user in event["recipients"]}
|
2016-10-28 18:50:21 +02:00
|
|
|
|
|
|
|
self.assertEqual(expected_recipient_ids, event_recipient_user_ids)
|
|
|
|
self.assertEqual(expected_recipient_ids, event_user_ids)
|
|
|
|
self.assertEqual(event_recipient_emails, expected_recipient_emails)
|
2021-02-12 08:20:45 +01:00
|
|
|
self.assertEqual(event["sender"]["email"], sender.email)
|
|
|
|
self.assertEqual(event["type"], "typing")
|
|
|
|
self.assertEqual(event["op"], "start")
|
2016-10-12 20:57:59 +02:00
|
|
|
|
2020-02-22 13:38:09 +01:00
|
|
|
def test_stop_to_self(self) -> None:
|
2016-10-12 20:57:59 +02:00
|
|
|
"""
|
|
|
|
Sending stopped typing notification to yourself
|
|
|
|
is successful.
|
|
|
|
"""
|
2021-02-12 08:20:45 +01:00
|
|
|
user = self.example_user("hamlet")
|
2017-05-08 16:23:43 +02:00
|
|
|
email = user.email
|
2020-04-09 21:51:58 +02:00
|
|
|
expected_recipient_emails = {email}
|
|
|
|
expected_recipient_ids = {user.id}
|
2016-10-12 20:57:59 +02:00
|
|
|
|
2023-04-05 13:36:01 +02:00
|
|
|
with self.capture_send_event_calls(expected_num_events=1) as events:
|
2020-02-22 13:38:09 +01:00
|
|
|
params = dict(
|
2020-08-07 01:09:47 +02:00
|
|
|
to=orjson.dumps([user.id]).decode(),
|
2021-02-12 08:20:45 +01:00
|
|
|
op="stop",
|
2020-02-22 13:38:09 +01:00
|
|
|
)
|
2021-02-12 08:20:45 +01:00
|
|
|
result = self.api_post(user, "/api/v1/typing", params)
|
2020-02-22 13:38:09 +01:00
|
|
|
|
2016-10-12 20:57:59 +02:00
|
|
|
self.assert_json_success(result)
|
2021-05-17 05:41:32 +02:00
|
|
|
self.assert_length(events, 1)
|
2016-10-12 20:57:59 +02:00
|
|
|
|
2021-02-12 08:20:45 +01:00
|
|
|
event = events[0]["event"]
|
|
|
|
event_recipient_emails = {user["email"] for user in event["recipients"]}
|
|
|
|
event_user_ids = set(events[0]["users"])
|
|
|
|
event_recipient_user_ids = {user["user_id"] for user in event["recipients"]}
|
2016-10-28 18:50:21 +02:00
|
|
|
|
|
|
|
self.assertEqual(expected_recipient_ids, event_recipient_user_ids)
|
|
|
|
self.assertEqual(expected_recipient_ids, event_user_ids)
|
|
|
|
self.assertEqual(event_recipient_emails, expected_recipient_emails)
|
2021-02-12 08:20:45 +01:00
|
|
|
self.assertEqual(event["sender"]["email"], email)
|
|
|
|
self.assertEqual(event["type"], "typing")
|
|
|
|
self.assertEqual(event["op"], "stop")
|
2016-10-12 20:57:59 +02:00
|
|
|
|
2020-02-22 13:38:09 +01:00
|
|
|
def test_stop_to_another_user(self) -> None:
|
2016-10-12 20:57:59 +02:00
|
|
|
"""
|
|
|
|
Sending stopped typing notification to another user
|
|
|
|
is successful.
|
|
|
|
"""
|
2021-02-12 08:20:45 +01:00
|
|
|
sender = self.example_user("hamlet")
|
|
|
|
recipient = self.example_user("othello")
|
2020-04-09 21:51:58 +02:00
|
|
|
expected_recipients = {sender, recipient}
|
|
|
|
expected_recipient_emails = {user.email for user in expected_recipients}
|
|
|
|
expected_recipient_ids = {user.id for user in expected_recipients}
|
2016-10-28 18:50:21 +02:00
|
|
|
|
2023-04-05 13:36:01 +02:00
|
|
|
with self.capture_send_event_calls(expected_num_events=1) as events:
|
2020-02-22 13:38:09 +01:00
|
|
|
params = dict(
|
2020-08-07 01:09:47 +02:00
|
|
|
to=orjson.dumps([recipient.id]).decode(),
|
2021-02-12 08:20:45 +01:00
|
|
|
op="stop",
|
2020-02-22 13:38:09 +01:00
|
|
|
)
|
2021-02-12 08:20:45 +01:00
|
|
|
result = self.api_post(sender, "/api/v1/typing", params)
|
2020-02-22 13:38:09 +01:00
|
|
|
|
2016-10-12 20:57:59 +02:00
|
|
|
self.assert_json_success(result)
|
2021-05-17 05:41:32 +02:00
|
|
|
self.assert_length(events, 1)
|
2016-10-12 20:57:59 +02:00
|
|
|
|
2021-02-12 08:20:45 +01:00
|
|
|
event = events[0]["event"]
|
|
|
|
event_recipient_emails = {user["email"] for user in event["recipients"]}
|
|
|
|
event_user_ids = set(events[0]["users"])
|
|
|
|
event_recipient_user_ids = {user["user_id"] for user in event["recipients"]}
|
2016-10-28 18:50:21 +02:00
|
|
|
|
|
|
|
self.assertEqual(expected_recipient_ids, event_recipient_user_ids)
|
|
|
|
self.assertEqual(expected_recipient_ids, event_user_ids)
|
|
|
|
self.assertEqual(event_recipient_emails, expected_recipient_emails)
|
2021-02-12 08:20:45 +01:00
|
|
|
self.assertEqual(event["sender"]["email"], sender.email)
|
|
|
|
self.assertEqual(event["type"], "typing")
|
|
|
|
self.assertEqual(event["op"], "stop")
|
2020-12-24 21:00:20 +01:00
|
|
|
|
|
|
|
|
|
|
|
class TypingHappyPathTestStreams(ZulipTestCase):
|
2024-04-10 20:48:10 +02:00
|
|
|
def test_valid_type_and_op_parameters(self) -> None:
|
|
|
|
recipient_type_name = ["channel", "stream"]
|
|
|
|
operator_type = ["start", "stop"]
|
|
|
|
sender = self.example_user("hamlet")
|
|
|
|
stream_name = self.get_streams(sender)[0]
|
|
|
|
stream_id = self.get_stream_id(stream_name)
|
|
|
|
topic_name = "Some topic"
|
|
|
|
|
|
|
|
for recipient_type in recipient_type_name:
|
|
|
|
for operator in operator_type:
|
|
|
|
params = dict(
|
|
|
|
type=recipient_type,
|
|
|
|
op=operator,
|
|
|
|
stream_id=str(stream_id),
|
|
|
|
topic=topic_name,
|
|
|
|
)
|
|
|
|
|
|
|
|
result = self.api_post(sender, "/api/v1/typing", params)
|
|
|
|
self.assert_json_success(result)
|
|
|
|
|
2020-12-24 21:00:20 +01:00
|
|
|
def test_start(self) -> None:
|
|
|
|
sender = self.example_user("hamlet")
|
|
|
|
stream_name = self.get_streams(sender)[0]
|
|
|
|
stream_id = self.get_stream_id(stream_name)
|
2024-01-15 12:17:50 +01:00
|
|
|
topic_name = "Some topic"
|
2020-12-24 21:00:20 +01:00
|
|
|
|
2023-11-07 15:49:13 +01:00
|
|
|
expected_user_ids = self.not_long_term_idle_subscriber_ids(stream_name, sender.realm)
|
2020-12-24 21:00:20 +01:00
|
|
|
|
|
|
|
params = dict(
|
|
|
|
type="stream",
|
|
|
|
op="start",
|
2023-10-12 09:13:34 +02:00
|
|
|
stream_id=str(stream_id),
|
2024-01-15 12:17:50 +01:00
|
|
|
topic=topic_name,
|
2020-12-24 21:00:20 +01:00
|
|
|
)
|
|
|
|
|
2023-11-14 22:57:16 +01:00
|
|
|
with self.assert_database_query_count(6):
|
2023-04-05 13:36:01 +02:00
|
|
|
with self.capture_send_event_calls(expected_num_events=1) as events:
|
2020-12-24 21:00:20 +01:00
|
|
|
result = self.api_post(sender, "/api/v1/typing", params)
|
|
|
|
self.assert_json_success(result)
|
2021-05-17 05:41:32 +02:00
|
|
|
self.assert_length(events, 1)
|
2020-12-24 21:00:20 +01:00
|
|
|
|
|
|
|
event = events[0]["event"]
|
|
|
|
event_user_ids = set(events[0]["users"])
|
|
|
|
|
|
|
|
self.assertEqual(expected_user_ids, event_user_ids)
|
|
|
|
self.assertEqual(sender.email, event["sender"]["email"])
|
|
|
|
self.assertEqual(stream_id, event["stream_id"])
|
2024-01-15 12:17:50 +01:00
|
|
|
self.assertEqual(topic_name, event["topic"])
|
2020-12-24 21:00:20 +01:00
|
|
|
self.assertEqual("typing", event["type"])
|
|
|
|
self.assertEqual("start", event["op"])
|
|
|
|
|
|
|
|
def test_stop(self) -> None:
|
|
|
|
sender = self.example_user("hamlet")
|
|
|
|
stream_name = self.get_streams(sender)[0]
|
|
|
|
stream_id = self.get_stream_id(stream_name)
|
2024-01-15 12:17:50 +01:00
|
|
|
topic_name = "Some topic"
|
2020-12-24 21:00:20 +01:00
|
|
|
|
2023-11-07 15:49:13 +01:00
|
|
|
expected_user_ids = self.not_long_term_idle_subscriber_ids(stream_name, sender.realm)
|
2020-12-24 21:00:20 +01:00
|
|
|
|
|
|
|
params = dict(
|
|
|
|
type="stream",
|
|
|
|
op="stop",
|
2023-10-12 09:13:34 +02:00
|
|
|
stream_id=str(stream_id),
|
2024-01-15 12:17:50 +01:00
|
|
|
topic=topic_name,
|
2020-12-24 21:00:20 +01:00
|
|
|
)
|
|
|
|
|
2023-11-14 22:57:16 +01:00
|
|
|
with self.assert_database_query_count(6):
|
2023-04-05 13:36:01 +02:00
|
|
|
with self.capture_send_event_calls(expected_num_events=1) as events:
|
2020-12-24 21:00:20 +01:00
|
|
|
result = self.api_post(sender, "/api/v1/typing", params)
|
|
|
|
self.assert_json_success(result)
|
2021-05-17 05:41:32 +02:00
|
|
|
self.assert_length(events, 1)
|
2020-12-24 21:00:20 +01:00
|
|
|
|
|
|
|
event = events[0]["event"]
|
|
|
|
event_user_ids = set(events[0]["users"])
|
|
|
|
|
|
|
|
self.assertEqual(expected_user_ids, event_user_ids)
|
|
|
|
self.assertEqual(sender.email, event["sender"]["email"])
|
|
|
|
self.assertEqual(stream_id, event["stream_id"])
|
2024-01-15 12:17:50 +01:00
|
|
|
self.assertEqual(topic_name, event["topic"])
|
2020-12-24 21:00:20 +01:00
|
|
|
self.assertEqual("typing", event["type"])
|
|
|
|
self.assertEqual("stop", event["op"])
|
2021-07-25 21:30:44 +02:00
|
|
|
|
2023-11-14 22:57:16 +01:00
|
|
|
def test_max_stream_size_for_typing_notifications_setting(self) -> None:
|
|
|
|
sender = self.example_user("hamlet")
|
|
|
|
stream_name = self.get_streams(sender)[0]
|
|
|
|
stream_id = self.get_stream_id(stream_name)
|
2024-01-15 12:17:50 +01:00
|
|
|
topic_name = "Some topic"
|
2023-11-14 22:57:16 +01:00
|
|
|
|
|
|
|
for name in ["aaron", "iago", "cordelia", "prospero", "othello", "polonius"]:
|
|
|
|
user = self.example_user(name)
|
|
|
|
self.subscribe(user, stream_name)
|
|
|
|
|
|
|
|
params = dict(
|
|
|
|
type="stream",
|
|
|
|
op="start",
|
|
|
|
stream_id=str(stream_id),
|
2024-01-15 12:17:50 +01:00
|
|
|
topic=topic_name,
|
2023-11-14 22:57:16 +01:00
|
|
|
)
|
|
|
|
with self.settings(MAX_STREAM_SIZE_FOR_TYPING_NOTIFICATIONS=5):
|
|
|
|
with self.assert_database_query_count(5):
|
|
|
|
with self.capture_send_event_calls(expected_num_events=0) as events:
|
|
|
|
result = self.api_post(sender, "/api/v1/typing", params)
|
|
|
|
self.assert_json_success(result)
|
|
|
|
self.assert_length(events, 0)
|
|
|
|
|
2023-11-07 15:49:13 +01:00
|
|
|
def test_notify_not_long_term_idle_subscribers_only(self) -> None:
|
|
|
|
sender = self.example_user("hamlet")
|
|
|
|
stream_name = self.get_streams(sender)[0]
|
|
|
|
stream_id = self.get_stream_id(stream_name)
|
2024-01-15 12:17:50 +01:00
|
|
|
topic_name = "Some topic"
|
2023-11-07 15:49:13 +01:00
|
|
|
|
|
|
|
aaron = self.example_user("aaron")
|
|
|
|
iago = self.example_user("iago")
|
|
|
|
for user in [aaron, iago]:
|
|
|
|
self.subscribe(user, stream_name)
|
|
|
|
self.soft_deactivate_user(user)
|
|
|
|
|
|
|
|
subscriber_ids = {
|
|
|
|
user_profile.id
|
|
|
|
for user_profile in self.users_subscribed_to_stream(stream_name, sender.realm)
|
|
|
|
}
|
|
|
|
not_long_term_idle_subscriber_ids = subscriber_ids - {aaron.id, iago.id}
|
|
|
|
|
|
|
|
params = dict(
|
|
|
|
type="stream",
|
|
|
|
op="start",
|
|
|
|
stream_id=str(stream_id),
|
2024-01-15 12:17:50 +01:00
|
|
|
topic=topic_name,
|
2023-11-07 15:49:13 +01:00
|
|
|
)
|
|
|
|
|
2023-11-14 22:57:16 +01:00
|
|
|
with self.assert_database_query_count(6):
|
2023-11-07 15:49:13 +01:00
|
|
|
with self.capture_send_event_calls(expected_num_events=1) as events:
|
|
|
|
result = self.api_post(sender, "/api/v1/typing", params)
|
|
|
|
self.assert_json_success(result)
|
|
|
|
self.assert_length(events, 1)
|
|
|
|
|
|
|
|
event = events[0]["event"]
|
|
|
|
event_user_ids = set(events[0]["users"])
|
|
|
|
|
|
|
|
# Only subscribers who are not long_term_idle are notified for typing notifications.
|
|
|
|
self.assertNotEqual(subscriber_ids, event_user_ids)
|
|
|
|
self.assertEqual(not_long_term_idle_subscriber_ids, event_user_ids)
|
|
|
|
|
|
|
|
self.assertEqual(sender.email, event["sender"]["email"])
|
|
|
|
self.assertEqual(stream_id, event["stream_id"])
|
2024-01-15 12:17:50 +01:00
|
|
|
self.assertEqual(topic_name, event["topic"])
|
2023-11-07 15:49:13 +01:00
|
|
|
self.assertEqual("typing", event["type"])
|
|
|
|
self.assertEqual("start", event["op"])
|
|
|
|
|
2021-07-25 21:30:44 +02:00
|
|
|
|
|
|
|
class TestSendTypingNotificationsSettings(ZulipTestCase):
|
|
|
|
def test_send_private_typing_notifications_setting(self) -> None:
|
|
|
|
sender = self.example_user("hamlet")
|
|
|
|
recipient_user = self.example_user("othello")
|
|
|
|
expected_recipients = {sender, recipient_user}
|
|
|
|
expected_recipient_ids = {user.id for user in expected_recipients}
|
|
|
|
|
|
|
|
params = dict(
|
|
|
|
to=orjson.dumps([recipient_user.id]).decode(),
|
|
|
|
op="start",
|
|
|
|
)
|
|
|
|
|
|
|
|
# Test typing events sent when `send_private_typing_notifications` set to `True`.
|
|
|
|
self.assertTrue(sender.send_private_typing_notifications)
|
|
|
|
|
2023-04-05 13:36:01 +02:00
|
|
|
with self.capture_send_event_calls(expected_num_events=1) as events:
|
2021-07-25 21:30:44 +02:00
|
|
|
result = self.api_post(sender, "/api/v1/typing", params)
|
|
|
|
|
|
|
|
self.assert_json_success(result)
|
|
|
|
self.assert_length(events, 1)
|
|
|
|
event_user_ids = set(events[0]["users"])
|
|
|
|
self.assertEqual(expected_recipient_ids, event_user_ids)
|
|
|
|
self.assertEqual(orjson.loads(result.content)["msg"], "")
|
|
|
|
|
|
|
|
sender.send_private_typing_notifications = False
|
|
|
|
sender.save()
|
|
|
|
|
|
|
|
# No events should be sent now
|
2023-04-05 13:36:01 +02:00
|
|
|
with self.capture_send_event_calls(expected_num_events=0) as events:
|
2021-07-25 21:30:44 +02:00
|
|
|
result = self.api_post(sender, "/api/v1/typing", params)
|
|
|
|
|
2023-01-24 15:36:03 +01:00
|
|
|
self.assert_json_error(result, "User has disabled typing notifications for direct messages")
|
2021-07-25 21:30:44 +02:00
|
|
|
self.assertEqual(events, [])
|
|
|
|
|
|
|
|
def test_send_stream_typing_notifications_setting(self) -> None:
|
|
|
|
sender = self.example_user("hamlet")
|
|
|
|
stream_name = self.get_streams(sender)[0]
|
|
|
|
stream_id = self.get_stream_id(stream_name)
|
2024-01-15 12:17:50 +01:00
|
|
|
topic_name = "Some topic"
|
2021-07-25 21:30:44 +02:00
|
|
|
|
2023-11-07 15:49:13 +01:00
|
|
|
expected_user_ids = self.not_long_term_idle_subscriber_ids(stream_name, sender.realm)
|
2021-07-25 21:30:44 +02:00
|
|
|
|
|
|
|
params = dict(
|
|
|
|
type="stream",
|
|
|
|
op="start",
|
2023-10-12 09:13:34 +02:00
|
|
|
stream_id=str(stream_id),
|
2024-01-15 12:17:50 +01:00
|
|
|
topic=topic_name,
|
2021-07-25 21:30:44 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
# Test typing events sent when `send_stream_typing_notifications` set to `True`.
|
|
|
|
self.assertTrue(sender.send_stream_typing_notifications)
|
|
|
|
|
2023-04-05 13:36:01 +02:00
|
|
|
with self.capture_send_event_calls(expected_num_events=1) as events:
|
2021-07-25 21:30:44 +02:00
|
|
|
result = self.api_post(sender, "/api/v1/typing", params)
|
|
|
|
self.assert_json_success(result)
|
|
|
|
self.assert_length(events, 1)
|
|
|
|
self.assertEqual(orjson.loads(result.content)["msg"], "")
|
|
|
|
event_user_ids = set(events[0]["users"])
|
|
|
|
self.assertEqual(expected_user_ids, event_user_ids)
|
|
|
|
|
|
|
|
sender.send_stream_typing_notifications = False
|
|
|
|
sender.save()
|
|
|
|
|
|
|
|
# No events should be sent now
|
2023-04-05 13:36:01 +02:00
|
|
|
with self.capture_send_event_calls(expected_num_events=0) as events:
|
2021-07-25 21:30:44 +02:00
|
|
|
result = self.api_post(sender, "/api/v1/typing", params)
|
2024-04-16 15:52:21 +02:00
|
|
|
self.assert_json_error(
|
|
|
|
result, "User has disabled typing notifications for channel messages"
|
|
|
|
)
|
2021-07-25 21:30:44 +02:00
|
|
|
self.assertEqual(events, [])
|
2024-04-12 19:30:29 +02:00
|
|
|
|
|
|
|
def test_typing_notifications_disabled(self) -> None:
|
|
|
|
sender = self.example_user("hamlet")
|
|
|
|
stream_name = self.get_streams(sender)[0]
|
|
|
|
stream_id = self.get_stream_id(stream_name)
|
|
|
|
topic_name = "Some topic"
|
|
|
|
|
|
|
|
aaron = self.example_user("aaron")
|
|
|
|
iago = self.example_user("iago")
|
|
|
|
for user in [aaron, iago]:
|
|
|
|
self.subscribe(user, stream_name)
|
|
|
|
|
|
|
|
aaron.receives_typing_notifications = False
|
|
|
|
aaron.save()
|
|
|
|
|
|
|
|
params = dict(
|
|
|
|
type="stream",
|
|
|
|
op="start",
|
|
|
|
stream_id=str(stream_id),
|
|
|
|
topic=topic_name,
|
|
|
|
)
|
|
|
|
|
|
|
|
with self.capture_send_event_calls(expected_num_events=1) as events:
|
|
|
|
result = self.api_post(sender, "/api/v1/typing", params)
|
|
|
|
self.assert_json_success(result)
|
|
|
|
self.assert_length(events, 1)
|
|
|
|
|
|
|
|
event_user_ids = set(events[0]["users"])
|
|
|
|
|
|
|
|
# Only users who have typing notifications enabled would receive
|
|
|
|
# notifications.
|
|
|
|
self.assertNotIn(aaron.id, event_user_ids)
|
|
|
|
self.assertIn(iago.id, event_user_ids)
|