diff --git a/zerver/tests/test_email_notifications.py b/zerver/tests/test_email_notifications.py index 0bf40b80b9..8a5e67e078 100644 --- a/zerver/tests/test_email_notifications.py +++ b/zerver/tests/test_email_notifications.py @@ -691,6 +691,47 @@ class TestMissedMessages(ZulipTestCase): trigger="mentioned", ) + def _extra_context_in_missed_stream_messages_followed_topic_wildcard_mention( + self, send_as_user: bool, show_message_content: bool = True + ) -> None: + for i in range(1, 6): + self.send_stream_message(self.example_user("othello"), "Denmark", content=str(i)) + self.send_stream_message(self.example_user("othello"), "Denmark", "11", topic_name="test2") + msg_id = self.send_stream_message(self.example_user("othello"), "Denmark", "@**all**") + + if show_message_content: + verify_body_include = [ + "Othello, the Moor of Venice: > 1 > 2 > 3 > 4 > 5 > @**all** -- ", + "You are receiving this because you have wildcard mention notifications enabled for topics you follow.", + ] + email_subject = "#Denmark > test" + verify_body_does_not_include: List[str] = [] + else: + # Test in case if message content in missed email message are disabled. + verify_body_include = [ + "This email does not include message content because you have disabled message ", + "http://zulip.testserver/help/pm-mention-alert-notifications ", + "View or reply in Zulip Dev Zulip", + " Manage email preferences: http://zulip.testserver/#settings/notifications", + ] + email_subject = "New messages" + verify_body_does_not_include = [ + "Othello, the Moor of Venice", + "1 2 3 4 5 @**all**", + "private", + "group", + "Reply to this email directly, or view it in Zulip Dev Zulip", + ] + self._test_cases( + msg_id, + verify_body_include, + email_subject, + send_as_user, + show_message_content=show_message_content, + verify_body_does_not_include=verify_body_does_not_include, + trigger="followed_topic_wildcard_mentioned", + ) + def _extra_context_in_missed_stream_messages_wildcard_mention( self, send_as_user: bool, show_message_content: bool = True ) -> None: @@ -1281,6 +1322,10 @@ class TestMissedMessages(ZulipTestCase): ) self._extra_context_in_missed_stream_messages_mention(False, show_message_content=False) mail.outbox = [] + self._extra_context_in_missed_stream_messages_followed_topic_wildcard_mention( + False, show_message_content=False + ) + mail.outbox = [] self._extra_context_in_missed_stream_messages_wildcard_mention( False, show_message_content=False ) @@ -1298,6 +1343,15 @@ class TestMissedMessages(ZulipTestCase): def test_extra_context_in_missed_stream_messages(self) -> None: self._extra_context_in_missed_stream_messages_mention(False) + @override_settings(SEND_MISSED_MESSAGE_EMAILS_AS_USER=True) + def test_extra_context_in_missed_stream_messages_as_user_followed_topic_wildcard( + self, + ) -> None: + self._extra_context_in_missed_stream_messages_followed_topic_wildcard_mention(True) + + def test_extra_context_in_missed_stream_messages_followed_topic_wildcard(self) -> None: + self._extra_context_in_missed_stream_messages_followed_topic_wildcard_mention(False) + @override_settings(SEND_MISSED_MESSAGE_EMAILS_AS_USER=True) def test_extra_context_in_missed_stream_messages_as_user_wildcard(self) -> None: self._extra_context_in_missed_stream_messages_wildcard_mention(True) @@ -1891,7 +1945,21 @@ class TestMissedMessages(ZulipTestCase): [{"message_id": personal_message_id, "trigger": "private_message"}], ) - # Wild card mention should NOT soft reactivate the user + # Followed Topic wildcard mention should NOT soft reactivate the user + with self.soft_deactivate_and_check_long_term_idle(hamlet, expected=True): + mention = "@**all**" + stream_mentioned_message_id = self.send_stream_message(othello, "Denmark", mention) + handle_missedmessage_emails( + hamlet.id, + [ + { + "message_id": stream_mentioned_message_id, + "trigger": "followed_topic_wildcard_mentioned", + } + ], + ) + + # Wildcard mention should NOT soft reactivate the user with self.soft_deactivate_and_check_long_term_idle(hamlet, expected=True): # Soft reactivate the user by sending a personal message mention = "@**all**" diff --git a/zerver/tests/test_event_queue.py b/zerver/tests/test_event_queue.py index 5455fc17f7..8d356d1554 100644 --- a/zerver/tests/test_event_queue.py +++ b/zerver/tests/test_event_queue.py @@ -875,6 +875,42 @@ class MissedMessageHookTest(ZulipTestCase): already_notified={"email_notified": True, "push_notified": True}, ) + def test_followed_topic_wildcard_mention_in_muted_stream(self) -> None: + # By default, wildcard mentions in a followed topic with muted stream DO notify. + do_change_user_setting( + self.user_profile, "wildcard_mentions_notify", False, acting_user=None + ) + do_change_user_setting( + self.user_profile, "enable_followed_topic_email_notifications", False, acting_user=None + ) + do_change_user_setting( + self.user_profile, "enable_followed_topic_push_notifications", False, acting_user=None + ) + + self.change_subscription_properties({"is_muted": True}) + do_set_user_topic_visibility_policy( + self.user_profile, + get_stream("Denmark", self.user_profile.realm), + "test", + visibility_policy=UserTopic.VisibilityPolicy.FOLLOWED, + ) + self.send_stream_message(self.user_profile, "Denmark") + + msg_id = self.send_stream_message(self.iago, "Denmark", content="@**all** what's up?") + with mock.patch("zerver.tornado.event_queue.maybe_enqueue_notifications") as mock_enqueue: + missedmessage_hook(self.user_profile.id, self.client_descriptor, True) + mock_enqueue.assert_called() + args_dict = mock_enqueue.call_args_list[1][1] + + self.assert_maybe_enqueue_notifications_call_args( + args_dict=args_dict, + message_id=msg_id, + user_id=self.user_profile.id, + followed_topic_wildcard_mention_email_notify=True, + followed_topic_wildcard_mention_push_notify=True, + already_notified={"email_notified": True, "push_notified": True}, + ) + def test_followed_topic_wildcard_mentions_notify_global_setting(self) -> None: do_change_user_setting( self.user_profile, "wildcard_mentions_notify", False, acting_user=None diff --git a/zerver/tests/test_message_edit.py b/zerver/tests/test_message_edit.py index 60057dd29d..9edc3636fa 100644 --- a/zerver/tests/test_message_edit.py +++ b/zerver/tests/test_message_edit.py @@ -2038,6 +2038,54 @@ class EditMessageTest(EditMessageTestCase): original_topic_state=UserTopic.VisibilityPolicy.UNMUTED, ) + @mock.patch("zerver.actions.message_edit.send_event") + def test_followed_topic_wildcard_mention(self, mock_send_event: mock.MagicMock) -> None: + stream_name = "Macbeth" + hamlet = self.example_user("hamlet") + cordelia = self.example_user("cordelia") + self.make_stream(stream_name, history_public_to_subscribers=True) + self.subscribe(hamlet, stream_name) + self.subscribe(cordelia, stream_name) + self.login_user(hamlet) + + do_set_user_topic_visibility_policy( + user_profile=hamlet, + stream=get_stream(stream_name, cordelia.realm), + topic="test", + visibility_policy=UserTopic.VisibilityPolicy.FOLLOWED, + ) + message_id = self.send_stream_message(hamlet, stream_name, "Hello everyone") + + def notify(user_id: int) -> Dict[str, Any]: + return { + "id": user_id, + "flags": ["wildcard_mentioned"], + } + + users_to_be_notified = sorted(map(notify, [cordelia.id, hamlet.id]), key=itemgetter("id")) + result = self.client_patch( + f"/json/messages/{message_id}", + { + "content": "Hello @**all**", + }, + ) + self.assert_json_success(result) + + # Extract the send_event call where event type is 'update_message'. + # Here we assert 'followed_topic_wildcard_mention_user_ids' + # has been set properly. + called = False + for call_args in mock_send_event.call_args_list: + (arg_realm, arg_event, arg_notified_users) = call_args[0] + if arg_event["type"] == "update_message": + self.assertEqual(arg_event["type"], "update_message") + self.assertEqual(arg_event["followed_topic_wildcard_mention_user_ids"], [hamlet.id]) + self.assertEqual( + sorted(arg_notified_users, key=itemgetter("id")), users_to_be_notified + ) + called = True + self.assertTrue(called) + @mock.patch("zerver.actions.message_edit.send_event") def test_wildcard_mention(self, mock_send_event: mock.MagicMock) -> None: stream_name = "Macbeth" diff --git a/zerver/tests/test_message_edit_notifications.py b/zerver/tests/test_message_edit_notifications.py index 43a5ae76c1..70973dc434 100644 --- a/zerver/tests/test_message_edit_notifications.py +++ b/zerver/tests/test_message_edit_notifications.py @@ -3,10 +3,12 @@ from unittest import mock from django.utils.timezone import now as timezone_now +from zerver.actions.user_settings import do_change_user_setting +from zerver.actions.user_topics import do_set_user_topic_visibility_policy from zerver.lib.push_notifications import get_apns_badge_count, get_apns_badge_count_future from zerver.lib.test_classes import ZulipTestCase from zerver.lib.test_helpers import mock_queue_publish -from zerver.models import Subscription, UserPresence +from zerver.models import Subscription, UserPresence, UserTopic, get_stream from zerver.tornado.event_queue import maybe_enqueue_notifications @@ -396,6 +398,52 @@ class EditMessageSideEffectsTest(ZulipTestCase): # actual content of these messages.) self.assert_length(info["queue_messages"], 2) + def test_updates_with_followed_topic_wildcard_mention(self) -> None: + cordelia = self.example_user("cordelia") + hamlet = self.example_user("hamlet") + self.subscribe(cordelia, "Scotland") + + do_change_user_setting( + cordelia, "enable_followed_topic_email_notifications", False, acting_user=None + ) + do_change_user_setting( + cordelia, "enable_followed_topic_push_notifications", False, acting_user=None + ) + do_change_user_setting(cordelia, "wildcard_mentions_notify", False, acting_user=None) + do_set_user_topic_visibility_policy( + user_profile=cordelia, + stream=get_stream("Scotland", cordelia.realm), + topic="test", + visibility_policy=UserTopic.VisibilityPolicy.FOLLOWED, + ) + + # We will simulate that the user still has an active client, + # but they don't have UserPresence rows, so we will still + # send offline notifications. + original_content = "no mention" + updated_content = "now we mention @**all**" + notification_message_data = self._send_and_update_message( + original_content, + updated_content, + connected_to_zulip=True, + ) + + message_id = notification_message_data["message_id"] + info = notification_message_data["info"] + + expected_enqueue_kwargs = self.get_maybe_enqueue_notifications_parameters( + user_id=cordelia.id, + acting_user_id=hamlet.id, + message_id=message_id, + followed_topic_wildcard_mention_email_notify=True, + followed_topic_wildcard_mention_push_notify=True, + already_notified={}, + ) + self.assertEqual(info["enqueue_kwargs"], expected_enqueue_kwargs) + + # messages will get enqueued. + self.assert_length(info["queue_messages"], 2) + def test_updates_with_wildcard_mention(self) -> None: cordelia = self.example_user("cordelia") hamlet = self.example_user("hamlet") diff --git a/zerver/tests/test_push_notifications.py b/zerver/tests/test_push_notifications.py index 4ebfb18eb8..b7e9aa8d39 100644 --- a/zerver/tests/test_push_notifications.py +++ b/zerver/tests/test_push_notifications.py @@ -1675,7 +1675,19 @@ class HandlePushNotificationTest(PushNotificationTest): {"message_id": personal_message_id, "trigger": "private_message"}, ) - # Wild card mention should NOT soft reactivate the user + # Followed Topic wildcard mention should NOT soft reactivate the user + with self.soft_deactivate_and_check_long_term_idle(self.user_profile, expected=True): + mention = "@**all**" + stream_mentioned_message_id = self.send_stream_message(othello, "Denmark", mention) + handle_push_notification( + self.user_profile.id, + { + "message_id": stream_mentioned_message_id, + "trigger": "followed_topic_wildcard_mentioned", + }, + ) + + # Wildcard mention should NOT soft reactivate the user with self.soft_deactivate_and_check_long_term_idle(self.user_profile, expected=True): # Soft reactivate the user by sending a personal message mention = "@**all**"