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:
Abhijeet Prasad Bodas
2021-07-01 21:10:16 +05:30
committed by Tim Abbott
parent 07d6ab9753
commit 167be7dbdc
5 changed files with 87 additions and 3 deletions

View File

@@ -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"]

View File

@@ -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]

View File

@@ -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}

View File

@@ -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()

View File

@@ -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={},
) )