muting: Don't enqueue notifications for messages from muted senders.

Earlier, the notification-blocking for messages from muted senders
was a side-effect of we never sending notifications for messages
with the "read" flag.

This commit decouples these two things, as a prep for having new
settings which will allow users to **always** receive email
notifications, including when/if they read the message during the
time the notifications is in the queue.

We still mark muted-sender messages as "read" when they are sent,
because that's desirable anyways.
This commit is contained in:
Abhijeet Prasad Bodas
2021-06-06 12:51:09 +05:30
committed by Tim Abbott
parent 006b92ed6d
commit 58da384da3
3 changed files with 86 additions and 0 deletions

View File

@@ -1968,6 +1968,7 @@ def do_send_messages(
stream_push_notify=(user_id in send_request.stream_push_user_ids),
stream_email_notify=(user_id in send_request.stream_email_user_ids),
wildcard_mention_notify=(user_id in send_request.wildcard_mention_user_ids),
sender_is_muted=(user_id in send_request.muted_sender_user_ids),
)
for user_id in user_list
]
@@ -5869,6 +5870,7 @@ def do_update_message(
event["online_push_user_ids"] = list(info["online_push_user_ids"])
event["stream_push_user_ids"] = list(info["stream_push_user_ids"])
event["stream_email_user_ids"] = list(info["stream_email_user_ids"])
event["muted_sender_user_ids"] = list(info["muted_sender_user_ids"])
event["prior_mention_user_ids"] = list(prior_mention_user_ids)
event["mention_user_ids"] = list(mention_user_ids)
event["presence_idle_user_ids"] = filter_presence_idle_user_ids(info["active_user_ids"])

View File

@@ -265,3 +265,75 @@ class MutedUsersTests(ZulipTestCase):
self.assert_usermessage_read_flag(othello, stream_message, False)
self.assert_usermessage_read_flag(othello, huddle_message, False)
self.assert_usermessage_read_flag(othello, pm_to_othello, False)
def test_muted_message_send_notifications_not_enqueued(self) -> None:
hamlet = self.example_user("hamlet")
self.login_user(hamlet)
cordelia = self.example_user("cordelia")
# No muting involved. Notification about to be enqueued for Hamlet.
with mock.patch("zerver.tornado.event_queue.maybe_enqueue_notifications") as m:
self.send_personal_message(cordelia, hamlet)
m.assert_called_once()
# Hamlet mutes Cordelia.
url = "/api/v1/users/me/muted_users/{}".format(cordelia.id)
result = self.api_post(hamlet, url)
self.assert_json_success(result)
# Cordelia has been muted. Notification will not be enqueued for Hamlet.
with mock.patch("zerver.tornado.event_queue.maybe_enqueue_notifications") as m:
self.send_personal_message(cordelia, hamlet)
m.assert_not_called()
def test_muted_message_edit_notifications_not_enqueued(self) -> None:
hamlet = self.example_user("hamlet")
self.login_user(hamlet)
cordelia = self.example_user("cordelia")
self.make_stream("general")
self.subscribe(hamlet, "general")
# No muting. Only Hamlet is subscribed to #general, so only he can potentially recieve
# notifications.
with mock.patch("zerver.tornado.event_queue.maybe_enqueue_notifications") as m:
message_id = self.send_stream_message(cordelia, "general")
# Message does not mention Hamlet, so no notification.
m.assert_not_called()
self.login("cordelia")
with mock.patch("zerver.tornado.event_queue.maybe_enqueue_notifications") as m:
result = self.client_patch(
"/json/messages/" + str(message_id),
dict(
message_id=message_id,
content="@**King Hamlet**",
),
)
self.assert_json_success(result)
m.assert_called_once()
# `maybe_enqueue_notificaions` was called for Hamlet after message edit mentioned him.
self.assertEqual(m.call_args_list[0][1]["user_profile_id"], hamlet.id)
# Hamlet mutes Cordelia.
self.login("hamlet")
url = "/api/v1/users/me/muted_users/{}".format(cordelia.id)
result = self.api_post(hamlet, url)
self.assert_json_success(result)
with mock.patch("zerver.tornado.event_queue.maybe_enqueue_notifications") as m:
message_id = self.send_stream_message(cordelia, "general")
m.assert_not_called()
self.login("cordelia")
with mock.patch("zerver.tornado.event_queue.maybe_enqueue_notifications") as m:
result = self.client_patch(
"/json/messages/" + str(message_id),
dict(
message_id=message_id,
content="@**King Hamlet**",
),
)
self.assert_json_success(result)
# `maybe_enqueue_notificaions` wasn't called for Hamlet after message edit which mentioned him,
# because the sender (Cordelia) was muted.
m.assert_not_called()

View File

@@ -954,6 +954,11 @@ def process_message_event(
and "wildcard_mentioned" in flags
and "read" not in flags
)
sender_is_muted = user_data.get("sender_is_muted", False)
if sender_is_muted:
# If the sender is muted, never enqueue notifications.
continue
# We first check if a message is potentially mentionable,
# since receiver_is_off_zulip is somewhat expensive.
@@ -1111,6 +1116,7 @@ def process_message_update_event(
stream_push_user_ids = set(event_template.pop("stream_push_user_ids", []))
stream_email_user_ids = set(event_template.pop("stream_email_user_ids", []))
wildcard_mention_user_ids = set(event_template.pop("wildcard_mention_user_ids", []))
muted_sender_user_ids = set(event_template.pop("muted_sender_user_ids", []))
# TODO/compatibility: Translation code for the rename of
# `push_notify_user_ids` to `online_push_user_ids`. Remove this
@@ -1146,6 +1152,7 @@ def process_message_update_event(
stream_name=stream_name,
online_push_enabled=(user_profile_id in online_push_user_ids),
presence_idle=(user_profile_id in presence_idle_user_ids),
muted_sender=(user_profile_id in muted_sender_user_ids),
prior_mentioned=(user_profile_id in prior_mention_user_ids),
)
@@ -1167,8 +1174,13 @@ def maybe_enqueue_notifications_for_message_update(
stream_name: Optional[str],
online_push_enabled: bool,
presence_idle: bool,
muted_sender: bool,
prior_mentioned: bool,
) -> None:
if muted_sender:
# Never send notifications if the sender has been muted
return
if private_message:
# We don't do offline notifications for PMs, because
# we already notified the user of the original message