2022-04-14 23:31:02 +02:00
|
|
|
from typing import List
|
|
|
|
|
2023-11-14 22:57:16 +01:00
|
|
|
from django.conf import settings
|
2022-04-14 23:31:02 +02:00
|
|
|
from django.utils.translation import gettext as _
|
|
|
|
|
|
|
|
from zerver.lib.exceptions import JsonableError
|
2023-11-07 15:49:13 +01:00
|
|
|
from zerver.lib.stream_subscription import get_active_subscriptions_for_stream_id
|
2023-12-15 01:16:00 +01:00
|
|
|
from zerver.models import Realm, Stream, UserProfile
|
|
|
|
from zerver.models.users import get_user_by_id_in_realm_including_cross_realm
|
2022-04-14 23:31:02 +02:00
|
|
|
from zerver.tornado.django_api import send_event
|
|
|
|
|
|
|
|
|
|
|
|
def do_send_typing_notification(
|
|
|
|
realm: Realm, sender: UserProfile, recipient_user_profiles: List[UserProfile], operator: str
|
|
|
|
) -> None:
|
|
|
|
sender_dict = {"user_id": sender.id, "email": sender.email}
|
|
|
|
|
|
|
|
# Include a list of recipients in the event body to help identify where the typing is happening
|
|
|
|
recipient_dicts = [
|
|
|
|
{"user_id": profile.id, "email": profile.email} for profile in recipient_user_profiles
|
|
|
|
]
|
|
|
|
event = dict(
|
|
|
|
type="typing",
|
2023-10-01 20:20:05 +02:00
|
|
|
message_type="direct",
|
2022-04-14 23:31:02 +02:00
|
|
|
op=operator,
|
|
|
|
sender=sender_dict,
|
|
|
|
recipients=recipient_dicts,
|
|
|
|
)
|
|
|
|
|
|
|
|
# Only deliver the notification to active user recipients
|
2024-04-12 19:30:29 +02:00
|
|
|
user_ids_to_notify = [
|
|
|
|
user.id
|
|
|
|
for user in recipient_user_profiles
|
|
|
|
if user.is_active and user.receives_typing_notifications
|
|
|
|
]
|
2022-04-14 23:31:02 +02:00
|
|
|
|
|
|
|
send_event(realm, event, user_ids_to_notify)
|
|
|
|
|
|
|
|
|
|
|
|
# check_send_typing_notification:
|
|
|
|
# Checks the typing notification and sends it
|
|
|
|
def check_send_typing_notification(sender: UserProfile, user_ids: List[int], operator: str) -> None:
|
|
|
|
realm = sender.realm
|
|
|
|
|
|
|
|
if sender.id not in user_ids:
|
|
|
|
user_ids.append(sender.id)
|
|
|
|
|
|
|
|
# If any of the user_ids being sent in are invalid, we will
|
|
|
|
# just reject the whole request, since a partial list of user_ids
|
2024-07-04 14:05:48 +02:00
|
|
|
# can create confusion related to direct message groups. Plus it's
|
|
|
|
# a good sign that a client is confused (or possibly even malicious)
|
|
|
|
# if we get bad user_ids.
|
2022-04-14 23:31:02 +02:00
|
|
|
user_profiles = []
|
|
|
|
for user_id in user_ids:
|
|
|
|
try:
|
|
|
|
# We include cross-bot realms as possible recipients,
|
2024-07-04 14:05:48 +02:00
|
|
|
# so that clients can know which direct message group
|
|
|
|
# conversation is relevant here.
|
2022-04-14 23:31:02 +02:00
|
|
|
user_profile = get_user_by_id_in_realm_including_cross_realm(user_id, sender.realm)
|
|
|
|
except UserProfile.DoesNotExist:
|
2023-07-17 22:40:33 +02:00
|
|
|
raise JsonableError(_("Invalid user ID {user_id}").format(user_id=user_id))
|
2022-04-14 23:31:02 +02:00
|
|
|
user_profiles.append(user_profile)
|
|
|
|
|
|
|
|
do_send_typing_notification(
|
|
|
|
realm=realm,
|
|
|
|
sender=sender,
|
|
|
|
recipient_user_profiles=user_profiles,
|
|
|
|
operator=operator,
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
def do_send_stream_typing_notification(
|
2024-01-13 09:55:16 +01:00
|
|
|
sender: UserProfile, operator: str, stream: Stream, topic_name: str
|
2022-04-14 23:31:02 +02:00
|
|
|
) -> None:
|
|
|
|
sender_dict = {"user_id": sender.id, "email": sender.email}
|
|
|
|
|
|
|
|
event = dict(
|
|
|
|
type="typing",
|
|
|
|
message_type="stream",
|
|
|
|
op=operator,
|
|
|
|
sender=sender_dict,
|
|
|
|
stream_id=stream.id,
|
2024-01-13 09:55:16 +01:00
|
|
|
topic=topic_name,
|
2022-04-14 23:31:02 +02:00
|
|
|
)
|
|
|
|
|
2023-11-07 15:49:13 +01:00
|
|
|
# We don't notify long_term_idle subscribers.
|
2023-11-14 22:57:16 +01:00
|
|
|
subscriptions_query = get_active_subscriptions_for_stream_id(
|
2023-11-07 15:49:13 +01:00
|
|
|
stream.id, include_deactivated_users=False
|
2023-11-14 22:57:16 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
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(
|
2024-04-12 19:30:29 +02:00
|
|
|
subscriptions_query.exclude(user_profile__long_term_idle=True)
|
|
|
|
.exclude(user_profile__receives_typing_notifications=False)
|
|
|
|
.values_list("user_profile_id", flat=True)
|
2023-11-14 22:57:16 +01:00
|
|
|
)
|
2022-04-14 23:31:02 +02:00
|
|
|
|
|
|
|
send_event(sender.realm, event, user_ids_to_notify)
|