mirror of
https://github.com/zulip/zulip.git
synced 2025-11-13 10:26:28 +00:00
mentions: Send user group mention data to notification notices.
We will later use this data to include text like: `<sender> mentioned @<user_group>` instead of the current `<sender> mentioned you` when someone mentions a user group the current user is a part of in email/push notification. Part of #13080.
This commit is contained in:
committed by
Tim Abbott
parent
07d6ab9753
commit
167be7dbdc
@@ -110,7 +110,7 @@ from zerver.lib.message import (
|
|||||||
update_first_visible_message_id,
|
update_first_visible_message_id,
|
||||||
wildcard_mention_allowed,
|
wildcard_mention_allowed,
|
||||||
)
|
)
|
||||||
from zerver.lib.notification_data import UserMessageNotificationsData
|
from zerver.lib.notification_data import UserMessageNotificationsData, get_user_group_mentions_data
|
||||||
from zerver.lib.pysa import mark_sanitized
|
from zerver.lib.pysa import mark_sanitized
|
||||||
from zerver.lib.queue import queue_json_publish
|
from zerver.lib.queue import queue_json_publish
|
||||||
from zerver.lib.realm_icon import realm_icon_url
|
from zerver.lib.realm_icon import realm_icon_url
|
||||||
@@ -1792,7 +1792,14 @@ def build_message_send_dict(
|
|||||||
message.rendered_content_version = markdown_version
|
message.rendered_content_version = markdown_version
|
||||||
links_for_embed = rendering_result.links_for_preview
|
links_for_embed = rendering_result.links_for_preview
|
||||||
|
|
||||||
# Add members of the mentioned user groups into `mentions_user_ids`.
|
mentioned_user_groups_map = get_user_group_mentions_data(
|
||||||
|
mentioned_user_ids=rendering_result.mentions_user_ids,
|
||||||
|
mentioned_user_group_ids=list(rendering_result.mentions_user_group_ids),
|
||||||
|
mention_data=mention_data,
|
||||||
|
)
|
||||||
|
|
||||||
|
# For single user as well as user group mentions, we set the `mentioned`
|
||||||
|
# flag on `UserMessage`
|
||||||
for group_id in rendering_result.mentions_user_group_ids:
|
for group_id in rendering_result.mentions_user_group_ids:
|
||||||
members = mention_data.get_group_members(group_id)
|
members = mention_data.get_group_members(group_id)
|
||||||
rendering_result.mentions_user_ids.update(members)
|
rendering_result.mentions_user_ids.update(members)
|
||||||
@@ -1823,6 +1830,7 @@ def build_message_send_dict(
|
|||||||
sender_queue_id=sender_queue_id,
|
sender_queue_id=sender_queue_id,
|
||||||
realm=realm,
|
realm=realm,
|
||||||
mention_data=mention_data,
|
mention_data=mention_data,
|
||||||
|
mentioned_user_groups_map=mentioned_user_groups_map,
|
||||||
message=message,
|
message=message,
|
||||||
rendering_result=rendering_result,
|
rendering_result=rendering_result,
|
||||||
active_user_ids=info["active_user_ids"],
|
active_user_ids=info["active_user_ids"],
|
||||||
@@ -1960,7 +1968,14 @@ def do_send_messages(
|
|||||||
users: List[Dict[str, Union[int, List[str]]]] = []
|
users: List[Dict[str, Union[int, List[str]]]] = []
|
||||||
for user_id in user_list:
|
for user_id in user_list:
|
||||||
flags = user_flags.get(user_id, [])
|
flags = user_flags.get(user_id, [])
|
||||||
users.append(dict(id=user_id, flags=flags))
|
user_data = dict(id=user_id, flags=flags)
|
||||||
|
|
||||||
|
if user_id in send_request.mentioned_user_groups_map:
|
||||||
|
user_data["mentioned_user_group_id"] = send_request.mentioned_user_groups_map[
|
||||||
|
user_id
|
||||||
|
]
|
||||||
|
|
||||||
|
users.append(user_data)
|
||||||
|
|
||||||
sender = send_request.message.sender
|
sender = send_request.message.sender
|
||||||
message_type = wide_message_dict["type"]
|
message_type = wide_message_dict["type"]
|
||||||
|
|||||||
@@ -96,6 +96,7 @@ class SendMessageRequest:
|
|||||||
sender_queue_id: Optional[str]
|
sender_queue_id: Optional[str]
|
||||||
realm: Realm
|
realm: Realm
|
||||||
mention_data: MentionData
|
mention_data: MentionData
|
||||||
|
mentioned_user_groups_map: Dict[int, int]
|
||||||
active_user_ids: Set[int]
|
active_user_ids: Set[int]
|
||||||
online_push_user_ids: Set[int]
|
online_push_user_ids: Set[int]
|
||||||
stream_push_user_ids: Set[int]
|
stream_push_user_ids: Set[int]
|
||||||
|
|||||||
@@ -1355,6 +1355,7 @@ Output:
|
|||||||
acting_user_id=acting_user_id,
|
acting_user_id=acting_user_id,
|
||||||
private_message=kwargs.get("private_message", False),
|
private_message=kwargs.get("private_message", False),
|
||||||
stream_name=kwargs.get("stream_name", None),
|
stream_name=kwargs.get("stream_name", None),
|
||||||
|
mentioned_user_group_id=kwargs.get("mentioned_user_group_id", None),
|
||||||
idle=kwargs.get("idle", True),
|
idle=kwargs.get("idle", True),
|
||||||
already_notified=kwargs.get(
|
already_notified=kwargs.get(
|
||||||
"already_notified", {"email_notified": False, "push_notified": False}
|
"already_notified", {"email_notified": False, "push_notified": False}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ from django.http import HttpRequest, HttpResponse
|
|||||||
from zerver.lib.actions import do_change_subscription_property, do_mute_topic
|
from zerver.lib.actions import do_change_subscription_property, do_mute_topic
|
||||||
from zerver.lib.test_classes import ZulipTestCase
|
from zerver.lib.test_classes import ZulipTestCase
|
||||||
from zerver.lib.test_helpers import HostRequestMock, mock_queue_publish
|
from zerver.lib.test_helpers import HostRequestMock, mock_queue_publish
|
||||||
|
from zerver.lib.user_groups import create_user_group, remove_user_from_user_group
|
||||||
from zerver.models import Recipient, Stream, Subscription, UserProfile, get_stream
|
from zerver.models import Recipient, Stream, Subscription, UserProfile, get_stream
|
||||||
from zerver.tornado.event_queue import (
|
from zerver.tornado.event_queue import (
|
||||||
ClientDescriptor,
|
ClientDescriptor,
|
||||||
@@ -54,6 +55,30 @@ class MissedMessageNotificationsTest(ZulipTestCase):
|
|||||||
self.assertTrue(notified["email_notified"])
|
self.assertTrue(notified["email_notified"])
|
||||||
self.assertTrue(notified["push_notified"])
|
self.assertTrue(notified["push_notified"])
|
||||||
|
|
||||||
|
with mock_queue_publish(
|
||||||
|
"zerver.tornado.event_queue.queue_json_publish"
|
||||||
|
) as mock_queue_json_publish:
|
||||||
|
params = self.get_maybe_enqueue_notifications_parameters(
|
||||||
|
message_id=1,
|
||||||
|
acting_user_id=2,
|
||||||
|
user_id=3,
|
||||||
|
private_message=False,
|
||||||
|
stream_name="Denmark",
|
||||||
|
flags=["mentioned"],
|
||||||
|
mentioned=True,
|
||||||
|
mentioned_user_group_id=33,
|
||||||
|
)
|
||||||
|
notified = maybe_enqueue_notifications(**params)
|
||||||
|
self.assertTrue(mock_queue_json_publish.call_count, 2)
|
||||||
|
|
||||||
|
push_notice = mock_queue_json_publish.call_args_list[0][0][1]
|
||||||
|
self.assertEqual(push_notice["stream_name"], "Denmark")
|
||||||
|
self.assertEqual(push_notice["mentioned_user_group_id"], 33)
|
||||||
|
|
||||||
|
email_notice = mock_queue_json_publish.call_args_list[1][0][1]
|
||||||
|
self.assertEqual(email_notice["stream_name"], "Denmark")
|
||||||
|
self.assertEqual(email_notice["mentioned_user_group_id"], 33)
|
||||||
|
|
||||||
def tornado_call(
|
def tornado_call(
|
||||||
self,
|
self,
|
||||||
view_func: Callable[[HttpRequest, UserProfile], HttpResponse],
|
view_func: Callable[[HttpRequest, UserProfile], HttpResponse],
|
||||||
@@ -106,6 +131,7 @@ class MissedMessageNotificationsTest(ZulipTestCase):
|
|||||||
"""Tests what arguments missedmessage_hook passes into maybe_enqueue_notifications.
|
"""Tests what arguments missedmessage_hook passes into maybe_enqueue_notifications.
|
||||||
Combined with the previous test, this ensures that the missedmessage_hook is correct"""
|
Combined with the previous test, this ensures that the missedmessage_hook is correct"""
|
||||||
user_profile = self.example_user("hamlet")
|
user_profile = self.example_user("hamlet")
|
||||||
|
cordelia = self.example_user("cordelia")
|
||||||
|
|
||||||
user_profile.enable_online_push_notifications = False
|
user_profile.enable_online_push_notifications = False
|
||||||
user_profile.save()
|
user_profile.save()
|
||||||
@@ -318,6 +344,33 @@ class MissedMessageNotificationsTest(ZulipTestCase):
|
|||||||
user_profile.save()
|
user_profile.save()
|
||||||
sub.save()
|
sub.save()
|
||||||
|
|
||||||
|
# Test with a user group mention
|
||||||
|
hamlet_and_cordelia = create_user_group(
|
||||||
|
"hamlet_and_cordelia", [user_profile, cordelia], cordelia.realm
|
||||||
|
)
|
||||||
|
client_descriptor = allocate_event_queue()
|
||||||
|
self.assertTrue(client_descriptor.event_queue.empty())
|
||||||
|
msg_id = self.send_stream_message(
|
||||||
|
iago, "Denmark", content="@*hamlet_and_cordelia* what's up?"
|
||||||
|
)
|
||||||
|
with mock.patch("zerver.tornado.event_queue.maybe_enqueue_notifications") as mock_enqueue:
|
||||||
|
missedmessage_hook(user_profile.id, client_descriptor, True)
|
||||||
|
mock_enqueue.assert_called_once()
|
||||||
|
args_dict = mock_enqueue.call_args_list[0][1]
|
||||||
|
|
||||||
|
assert_maybe_enqueue_notifications_call_args(
|
||||||
|
args_dict=args_dict,
|
||||||
|
message_id=msg_id,
|
||||||
|
flags=["mentioned"],
|
||||||
|
mentioned=True,
|
||||||
|
stream_name="Denmark",
|
||||||
|
mentioned_user_group_id=hamlet_and_cordelia.id,
|
||||||
|
already_notified={"email_notified": True, "push_notified": True},
|
||||||
|
)
|
||||||
|
destroy_event_queue(client_descriptor.event_queue.id)
|
||||||
|
remove_user_from_user_group(user_profile, hamlet_and_cordelia)
|
||||||
|
remove_user_from_user_group(cordelia, hamlet_and_cordelia)
|
||||||
|
|
||||||
# Test the hook with a stream message with stream_push_notify
|
# Test the hook with a stream message with stream_push_notify
|
||||||
change_subscription_properties(user_profile, stream, sub, {"push_notifications": True})
|
change_subscription_properties(user_profile, stream, sub, {"push_notifications": True})
|
||||||
client_descriptor = allocate_event_queue()
|
client_descriptor = allocate_event_queue()
|
||||||
|
|||||||
@@ -757,6 +757,7 @@ def missedmessage_hook(
|
|||||||
)
|
)
|
||||||
|
|
||||||
private_message = event["message"]["type"] == "private"
|
private_message = event["message"]["type"] == "private"
|
||||||
|
mentioned_user_group_id = internal_data.get("mentioned_user_group_id")
|
||||||
|
|
||||||
stream_name = None
|
stream_name = None
|
||||||
if not private_message:
|
if not private_message:
|
||||||
@@ -777,6 +778,7 @@ def missedmessage_hook(
|
|||||||
message_id=message_id,
|
message_id=message_id,
|
||||||
private_message=private_message,
|
private_message=private_message,
|
||||||
stream_name=stream_name,
|
stream_name=stream_name,
|
||||||
|
mentioned_user_group_id=mentioned_user_group_id,
|
||||||
idle=idle,
|
idle=idle,
|
||||||
already_notified=already_notified,
|
already_notified=already_notified,
|
||||||
)
|
)
|
||||||
@@ -800,6 +802,7 @@ def maybe_enqueue_notifications(
|
|||||||
message_id: int,
|
message_id: int,
|
||||||
private_message: bool,
|
private_message: bool,
|
||||||
stream_name: Optional[str],
|
stream_name: Optional[str],
|
||||||
|
mentioned_user_group_id: Optional[int],
|
||||||
idle: bool,
|
idle: bool,
|
||||||
already_notified: Dict[str, bool],
|
already_notified: Dict[str, bool],
|
||||||
) -> Dict[str, bool]:
|
) -> Dict[str, bool]:
|
||||||
@@ -818,6 +821,7 @@ def maybe_enqueue_notifications(
|
|||||||
private_message, acting_user_id, idle
|
private_message, acting_user_id, idle
|
||||||
)
|
)
|
||||||
notice["stream_name"] = stream_name
|
notice["stream_name"] = stream_name
|
||||||
|
notice["mentioned_user_group_id"] = mentioned_user_group_id
|
||||||
if not already_notified.get("push_notified"):
|
if not already_notified.get("push_notified"):
|
||||||
queue_json_publish("missedmessage_mobile_notifications", notice)
|
queue_json_publish("missedmessage_mobile_notifications", notice)
|
||||||
notified["push_notified"] = True
|
notified["push_notified"] = True
|
||||||
@@ -832,6 +836,7 @@ def maybe_enqueue_notifications(
|
|||||||
private_message, acting_user_id, idle
|
private_message, acting_user_id, idle
|
||||||
)
|
)
|
||||||
notice["stream_name"] = stream_name
|
notice["stream_name"] = stream_name
|
||||||
|
notice["mentioned_user_group_id"] = mentioned_user_group_id
|
||||||
if not already_notified.get("email_notified"):
|
if not already_notified.get("email_notified"):
|
||||||
queue_json_publish("missedmessage_emails", notice, lambda notice: None)
|
queue_json_publish("missedmessage_emails", notice, lambda notice: None)
|
||||||
notified["email_notified"] = True
|
notified["email_notified"] = True
|
||||||
@@ -933,6 +938,7 @@ def process_message_event(
|
|||||||
for user_data in users:
|
for user_data in users:
|
||||||
user_profile_id: int = user_data["id"]
|
user_profile_id: int = user_data["id"]
|
||||||
flags: Collection[str] = user_data.get("flags", [])
|
flags: Collection[str] = user_data.get("flags", [])
|
||||||
|
mentioned_user_group_id: Optional[int] = user_data.get("mentioned_user_group_id")
|
||||||
|
|
||||||
# If the recipient was offline and the message was a single or group PM to them
|
# If the recipient was offline and the message was a single or group PM to them
|
||||||
# or they were @-notified potentially notify more immediately
|
# or they were @-notified potentially notify more immediately
|
||||||
@@ -951,6 +957,7 @@ def process_message_event(
|
|||||||
# Remove fields sent through other pipes to save some space.
|
# Remove fields sent through other pipes to save some space.
|
||||||
internal_data.pop("flags")
|
internal_data.pop("flags")
|
||||||
internal_data.pop("user_id")
|
internal_data.pop("user_id")
|
||||||
|
internal_data["mentioned_user_group_id"] = mentioned_user_group_id
|
||||||
extra_user_data[user_profile_id] = dict(internal_data=internal_data)
|
extra_user_data[user_profile_id] = dict(internal_data=internal_data)
|
||||||
|
|
||||||
# If the message isn't notifiable had the user been idle, then the user
|
# If the message isn't notifiable had the user been idle, then the user
|
||||||
@@ -973,6 +980,7 @@ def process_message_event(
|
|||||||
message_id=message_id,
|
message_id=message_id,
|
||||||
private_message=private_message,
|
private_message=private_message,
|
||||||
stream_name=stream_name,
|
stream_name=stream_name,
|
||||||
|
mentioned_user_group_id=mentioned_user_group_id,
|
||||||
idle=idle,
|
idle=idle,
|
||||||
already_notified={},
|
already_notified={},
|
||||||
)
|
)
|
||||||
@@ -1196,12 +1204,18 @@ def maybe_enqueue_notifications_for_message_update(
|
|||||||
|
|
||||||
idle = presence_idle or receiver_is_off_zulip(user_notifications_data.user_id)
|
idle = presence_idle or receiver_is_off_zulip(user_notifications_data.user_id)
|
||||||
|
|
||||||
|
# We don't yet support custom user group mentions for message edit notifications.
|
||||||
|
# Users will still receive notifications (because of the mentioned flag), but those
|
||||||
|
# will be as if they were mentioned personally.
|
||||||
|
mentioned_user_group_id = None
|
||||||
|
|
||||||
maybe_enqueue_notifications(
|
maybe_enqueue_notifications(
|
||||||
user_notifications_data=user_notifications_data,
|
user_notifications_data=user_notifications_data,
|
||||||
message_id=message_id,
|
message_id=message_id,
|
||||||
acting_user_id=acting_user_id,
|
acting_user_id=acting_user_id,
|
||||||
private_message=private_message,
|
private_message=private_message,
|
||||||
stream_name=stream_name,
|
stream_name=stream_name,
|
||||||
|
mentioned_user_group_id=mentioned_user_group_id,
|
||||||
idle=idle,
|
idle=idle,
|
||||||
already_notified={},
|
already_notified={},
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user