mirror of https://github.com/zulip/zulip.git
typing_notifications: Don't notify long_term_idle subscribers.
The event for stream typing notifications is no longer sent to the long_term_idle subscribers of the stream. This helps to reduce the tornado's work of parsing super-long JSON-encoded lists of user IDs in large streams. Now the lists are shorter.
This commit is contained in:
parent
6e9da8ab2a
commit
e6e156709a
|
@ -3,7 +3,7 @@ from typing import List
|
||||||
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
|
||||||
from zerver.lib.stream_subscription import get_user_ids_for_streams
|
from zerver.lib.stream_subscription import get_active_subscriptions_for_stream_id
|
||||||
from zerver.models import Realm, Stream, UserProfile, get_user_by_id_in_realm_including_cross_realm
|
from zerver.models import Realm, Stream, UserProfile, get_user_by_id_in_realm_including_cross_realm
|
||||||
from zerver.tornado.django_api import send_event
|
from zerver.tornado.django_api import send_event
|
||||||
|
|
||||||
|
@ -77,6 +77,10 @@ def do_send_stream_typing_notification(
|
||||||
topic=topic,
|
topic=topic,
|
||||||
)
|
)
|
||||||
|
|
||||||
user_ids_to_notify = get_user_ids_for_streams({stream.id})[stream.id]
|
# We don't notify long_term_idle subscribers.
|
||||||
|
subscriptions = get_active_subscriptions_for_stream_id(
|
||||||
|
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))
|
||||||
|
|
||||||
send_event(sender.realm, event, user_ids_to_notify)
|
send_event(sender.realm, event, user_ids_to_notify)
|
||||||
|
|
|
@ -1186,6 +1186,17 @@ Output:
|
||||||
|
|
||||||
return [subscription.user_profile for subscription in subscriptions]
|
return [subscription.user_profile for subscription in subscriptions]
|
||||||
|
|
||||||
|
def not_long_term_idle_subscriber_ids(self, stream_name: str, realm: Realm) -> Set[int]:
|
||||||
|
stream = Stream.objects.get(name=stream_name, realm=realm)
|
||||||
|
recipient = Recipient.objects.get(type_id=stream.id, type=Recipient.STREAM)
|
||||||
|
|
||||||
|
subscriptions = Subscription.objects.filter(
|
||||||
|
recipient=recipient, active=True, is_user_active=True
|
||||||
|
).exclude(user_profile__long_term_idle=True)
|
||||||
|
user_profile_ids = set(subscriptions.values_list("user_profile_id", flat=True))
|
||||||
|
|
||||||
|
return user_profile_ids
|
||||||
|
|
||||||
def assert_json_success(
|
def assert_json_success(
|
||||||
self,
|
self,
|
||||||
result: Union["TestHttpResponse", HttpResponse],
|
result: Union["TestHttpResponse", HttpResponse],
|
||||||
|
|
|
@ -372,10 +372,7 @@ class TypingHappyPathTestStreams(ZulipTestCase):
|
||||||
stream_id = self.get_stream_id(stream_name)
|
stream_id = self.get_stream_id(stream_name)
|
||||||
topic = "Some topic"
|
topic = "Some topic"
|
||||||
|
|
||||||
expected_user_ids = {
|
expected_user_ids = self.not_long_term_idle_subscriber_ids(stream_name, sender.realm)
|
||||||
user_profile.id
|
|
||||||
for user_profile in self.users_subscribed_to_stream(stream_name, sender.realm)
|
|
||||||
}
|
|
||||||
|
|
||||||
params = dict(
|
params = dict(
|
||||||
type="stream",
|
type="stream",
|
||||||
|
@ -406,10 +403,7 @@ class TypingHappyPathTestStreams(ZulipTestCase):
|
||||||
stream_id = self.get_stream_id(stream_name)
|
stream_id = self.get_stream_id(stream_name)
|
||||||
topic = "Some topic"
|
topic = "Some topic"
|
||||||
|
|
||||||
expected_user_ids = {
|
expected_user_ids = self.not_long_term_idle_subscriber_ids(stream_name, sender.realm)
|
||||||
user_profile.id
|
|
||||||
for user_profile in self.users_subscribed_to_stream(stream_name, sender.realm)
|
|
||||||
}
|
|
||||||
|
|
||||||
params = dict(
|
params = dict(
|
||||||
type="stream",
|
type="stream",
|
||||||
|
@ -434,6 +428,50 @@ 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_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)
|
||||||
|
topic = "Some topic"
|
||||||
|
|
||||||
|
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),
|
||||||
|
topic=topic,
|
||||||
|
)
|
||||||
|
|
||||||
|
with self.assert_database_query_count(5):
|
||||||
|
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"])
|
||||||
|
self.assertEqual(topic, event["topic"])
|
||||||
|
self.assertEqual("typing", event["type"])
|
||||||
|
self.assertEqual("start", event["op"])
|
||||||
|
|
||||||
|
|
||||||
class TestSendTypingNotificationsSettings(ZulipTestCase):
|
class TestSendTypingNotificationsSettings(ZulipTestCase):
|
||||||
def test_send_private_typing_notifications_setting(self) -> None:
|
def test_send_private_typing_notifications_setting(self) -> None:
|
||||||
|
@ -475,10 +513,7 @@ class TestSendTypingNotificationsSettings(ZulipTestCase):
|
||||||
stream_id = self.get_stream_id(stream_name)
|
stream_id = self.get_stream_id(stream_name)
|
||||||
topic = "Some topic"
|
topic = "Some topic"
|
||||||
|
|
||||||
expected_user_ids = {
|
expected_user_ids = self.not_long_term_idle_subscriber_ids(stream_name, sender.realm)
|
||||||
user_profile.id
|
|
||||||
for user_profile in self.users_subscribed_to_stream(stream_name, sender.realm)
|
|
||||||
}
|
|
||||||
|
|
||||||
params = dict(
|
params = dict(
|
||||||
type="stream",
|
type="stream",
|
||||||
|
|
Loading…
Reference in New Issue