mirror of https://github.com/zulip/zulip.git
typing: Limit typing notifications in large streams.
This commit is contained in:
parent
f8a0035215
commit
2e2997bd7d
|
@ -2,8 +2,10 @@
|
||||||
|
|
||||||
The Zulip web app displays typing notifications in [conversation
|
The Zulip web app displays typing notifications in [conversation
|
||||||
views](/help/reading-conversations) and [**All direct
|
views](/help/reading-conversations) and [**All direct
|
||||||
messages**](/help/direct-messages#access-all-dms). The mobile app displays
|
messages**](/help/direct-messages#access-all-dms). Typing
|
||||||
typing notifications in direct message conversations.
|
notifications are not shown in streams with more than 100
|
||||||
|
subscribers. The mobile app displays typing notifications in direct
|
||||||
|
message conversations.
|
||||||
|
|
||||||
Typing notifications are only sent while one is actively editing text in
|
Typing notifications are only sent while one is actively editing text in
|
||||||
the compose box. They disappear if typing is paused for several seconds,
|
the compose box. They disappear if typing is paused for several seconds,
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
|
|
||||||
from zerver.lib.exceptions import JsonableError
|
from zerver.lib.exceptions import JsonableError
|
||||||
|
@ -78,9 +79,20 @@ def do_send_stream_typing_notification(
|
||||||
)
|
)
|
||||||
|
|
||||||
# We don't notify long_term_idle subscribers.
|
# We don't notify long_term_idle subscribers.
|
||||||
subscriptions = get_active_subscriptions_for_stream_id(
|
subscriptions_query = get_active_subscriptions_for_stream_id(
|
||||||
stream.id, include_deactivated_users=False
|
stream.id, include_deactivated_users=False
|
||||||
).exclude(user_profile__long_term_idle=True)
|
)
|
||||||
user_ids_to_notify = set(subscriptions.values_list("user_profile_id", flat=True))
|
|
||||||
|
total_subscriptions = subscriptions_query.count()
|
||||||
|
if total_subscriptions > settings.MAX_STREAM_SIZE_FOR_TYPING_NOTIFICATIONS:
|
||||||
|
# TODO: Stream typing notifications are disabled in streams
|
||||||
|
# with too many subscribers for performance reasons.
|
||||||
|
return
|
||||||
|
|
||||||
|
user_ids_to_notify = set(
|
||||||
|
subscriptions_query.exclude(user_profile__long_term_idle=True).values_list(
|
||||||
|
"user_profile_id", flat=True
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
send_event(sender.realm, event, user_ids_to_notify)
|
send_event(sender.realm, event, user_ids_to_notify)
|
||||||
|
|
|
@ -381,7 +381,7 @@ class TypingHappyPathTestStreams(ZulipTestCase):
|
||||||
topic=topic,
|
topic=topic,
|
||||||
)
|
)
|
||||||
|
|
||||||
with self.assert_database_query_count(5):
|
with self.assert_database_query_count(6):
|
||||||
with self.capture_send_event_calls(expected_num_events=1) as events:
|
with self.capture_send_event_calls(expected_num_events=1) as events:
|
||||||
result = self.api_post(sender, "/api/v1/typing", params)
|
result = self.api_post(sender, "/api/v1/typing", params)
|
||||||
self.assert_json_success(result)
|
self.assert_json_success(result)
|
||||||
|
@ -412,7 +412,7 @@ class TypingHappyPathTestStreams(ZulipTestCase):
|
||||||
topic=topic,
|
topic=topic,
|
||||||
)
|
)
|
||||||
|
|
||||||
with self.assert_database_query_count(5):
|
with self.assert_database_query_count(6):
|
||||||
with self.capture_send_event_calls(expected_num_events=1) as events:
|
with self.capture_send_event_calls(expected_num_events=1) as events:
|
||||||
result = self.api_post(sender, "/api/v1/typing", params)
|
result = self.api_post(sender, "/api/v1/typing", params)
|
||||||
self.assert_json_success(result)
|
self.assert_json_success(result)
|
||||||
|
@ -428,6 +428,29 @@ class TypingHappyPathTestStreams(ZulipTestCase):
|
||||||
self.assertEqual("typing", event["type"])
|
self.assertEqual("typing", event["type"])
|
||||||
self.assertEqual("stop", event["op"])
|
self.assertEqual("stop", event["op"])
|
||||||
|
|
||||||
|
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)
|
||||||
|
topic = "Some topic"
|
||||||
|
|
||||||
|
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),
|
||||||
|
topic=topic,
|
||||||
|
)
|
||||||
|
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)
|
||||||
|
|
||||||
def test_notify_not_long_term_idle_subscribers_only(self) -> None:
|
def test_notify_not_long_term_idle_subscribers_only(self) -> None:
|
||||||
sender = self.example_user("hamlet")
|
sender = self.example_user("hamlet")
|
||||||
stream_name = self.get_streams(sender)[0]
|
stream_name = self.get_streams(sender)[0]
|
||||||
|
@ -453,7 +476,7 @@ class TypingHappyPathTestStreams(ZulipTestCase):
|
||||||
topic=topic,
|
topic=topic,
|
||||||
)
|
)
|
||||||
|
|
||||||
with self.assert_database_query_count(5):
|
with self.assert_database_query_count(6):
|
||||||
with self.capture_send_event_calls(expected_num_events=1) as events:
|
with self.capture_send_event_calls(expected_num_events=1) as events:
|
||||||
result = self.api_post(sender, "/api/v1/typing", params)
|
result = self.api_post(sender, "/api/v1/typing", params)
|
||||||
self.assert_json_success(result)
|
self.assert_json_success(result)
|
||||||
|
|
|
@ -587,3 +587,8 @@ TYPING_STOPPED_WAIT_PERIOD_MILLISECONDS = 5000
|
||||||
# How often a client should send start notifications to the server to
|
# How often a client should send start notifications to the server to
|
||||||
# indicate that the user is still interacting with the compose UI.
|
# indicate that the user is still interacting with the compose UI.
|
||||||
TYPING_STARTED_WAIT_PERIOD_MILLISECONDS = 10000
|
TYPING_STARTED_WAIT_PERIOD_MILLISECONDS = 10000
|
||||||
|
|
||||||
|
# The maximum number of subscribers for a stream to have typing
|
||||||
|
# notifications enabled. Default is set to avoid excessive Tornado
|
||||||
|
# load in large organizations.
|
||||||
|
MAX_STREAM_SIZE_FOR_TYPING_NOTIFICATIONS = 100
|
||||||
|
|
Loading…
Reference in New Issue