From b052c8980ecc7bdb2a58ed08c8971079c28177b8 Mon Sep 17 00:00:00 2001 From: Prakhar Pratyush Date: Fri, 2 Jun 2023 13:12:58 +0530 Subject: [PATCH] settings: Add wildcard mention notifications for the followed topics. This commit makes it possible for users to control the wildcard mention notifications for messages sent to followed topics via a global notification setting. There is no support for configuring this setting through the UI yet. --- api_docs/changelog.md | 6 +- templates/zerver/emails/missed_message.html | 2 + templates/zerver/emails/missed_message.txt | 2 + zerver/actions/message_edit.py | 4 + zerver/actions/message_send.py | 26 +++++-- zerver/lib/email_notifications.py | 5 +- zerver/lib/message.py | 2 + zerver/lib/notification_data.py | 21 ++++++ zerver/lib/test_classes.py | 6 ++ .../0331_scheduledmessagenotificationemail.py | 4 + zerver/models.py | 3 + zerver/openapi/zulip.yaml | 34 +++++++++ zerver/tests/test_event_queue.py | 74 +++++++++++++++++++ zerver/tests/test_notification_data.py | 21 ++++++ zerver/tests/test_users.py | 15 +++- zerver/tornado/event_queue.py | 14 ++++ zerver/views/realm.py | 3 + zerver/views/user_settings.py | 3 + 18 files changed, 234 insertions(+), 11 deletions(-) diff --git a/api_docs/changelog.md b/api_docs/changelog.md index 88b97adb0d..65357a09d0 100644 --- a/api_docs/changelog.md +++ b/api_docs/changelog.md @@ -24,9 +24,9 @@ format used by the Zulip server that they are interacting with. * [`PATCH /realm/user_settings_defaults`](/api/update-realm-user-settings-defaults), [`POST /register`](/api/register-queue), [`PATCH /settings`](/api/update-settings): - Added `enable_followed_topic_email_notifications` and `enable_followed_topic_push_notifications` - boolean fields to control email and push notifications, respectively, for messages - sent to followed topics. + Added `enable_followed_topic_email_notifications`, `enable_followed_topic_push_notifications` + and `enable_followed_topic_wildcard_mentions_notify` boolean fields to control email, push + and wildcard mention notifications, respectively, for messages sent to followed topics. **Feature level 188** diff --git a/templates/zerver/emails/missed_message.html b/templates/zerver/emails/missed_message.html index 37adba30e1..d87a3668bb 100644 --- a/templates/zerver/emails/missed_message.html +++ b/templates/zerver/emails/missed_message.html @@ -31,6 +31,8 @@ {% trans %}You are receiving this because @{{ mentioned_user_group_name }} was mentioned.{% endtrans %}
{% elif wildcard_mentioned %} {% trans %}You are receiving this because everyone was mentioned in #{{ stream_name }}.{% endtrans %}
+ {% elif followed_topic_wildcard_mentioned %} + {% trans %}You are receiving this because you have wildcard mention notifications enabled for topics you follow.{% endtrans %}
{% elif stream_email_notify %} {% trans %}You are receiving this because you have email notifications enabled for #{{ stream_name }}.{% endtrans %}
{% elif followed_topic_email_notify %} diff --git a/templates/zerver/emails/missed_message.txt b/templates/zerver/emails/missed_message.txt index b0319647e9..8536a96723 100644 --- a/templates/zerver/emails/missed_message.txt +++ b/templates/zerver/emails/missed_message.txt @@ -27,6 +27,8 @@ See {{ alert_notif_url }} for more details. {% trans %}You are receiving this because @{{ mentioned_user_group_name }} was mentioned.{% endtrans %} {% elif wildcard_mentioned %} {% trans %}You are receiving this because everyone was mentioned in #{{ stream_name }}.{% endtrans %} +{% elif followed_topic_wildcard_mentioned %} +{% trans %}You are receiving this because you have wildcard mention notifications enabled for topics you follow.{% endtrans %} {% elif stream_email_notify %} {% trans %}You are receiving this because you have email notifications enabled for #{{ stream_name }}.{% endtrans %} {% elif followed_topic_email_notify %} diff --git a/zerver/actions/message_edit.py b/zerver/actions/message_edit.py index 23f568ec2d..b49dcfc5f8 100644 --- a/zerver/actions/message_edit.py +++ b/zerver/actions/message_edit.py @@ -481,8 +481,12 @@ def do_update_message( event["all_bot_user_ids"] = list(info.all_bot_user_ids) if rendering_result.mentions_wildcard: event["wildcard_mention_user_ids"] = list(info.wildcard_mention_user_ids) + event["followed_topic_wildcard_mention_user_ids"] = list( + info.followed_topic_wildcard_mention_user_ids + ) else: event["wildcard_mention_user_ids"] = [] + event["followed_topic_wildcard_mention_user_ids"] = [] do_update_mobile_push_notification( target_message, diff --git a/zerver/actions/message_send.py b/zerver/actions/message_send.py index 649d7a7a0a..69eae21794 100644 --- a/zerver/actions/message_send.py +++ b/zerver/actions/message_send.py @@ -168,6 +168,7 @@ class RecipientInfoResult: wildcard_mention_user_ids: Set[int] followed_topic_email_user_ids: Set[int] followed_topic_push_user_ids: Set[int] + followed_topic_wildcard_mention_user_ids: Set[int] muted_sender_user_ids: Set[int] um_eligible_user_ids: Set[int] long_term_idle_user_ids: Set[int] @@ -200,6 +201,7 @@ def get_recipient_info( wildcard_mention_user_ids: Set[int] = set() followed_topic_push_user_ids: Set[int] = set() followed_topic_email_user_ids: Set[int] = set() + followed_topic_wildcard_mention_user_ids: Set[int] = set() muted_sender_user_ids: Set[int] = get_muting_users(sender_id) if recipient.type == Recipient.PERSONAL: @@ -234,6 +236,9 @@ def get_recipient_info( followed_topic_push_notifications=F( "user_profile__enable_followed_topic_push_notifications" ), + followed_topic_wildcard_mentions_notify=F( + "user_profile__enable_followed_topic_wildcard_mentions_notify" + ), ) .values( "user_profile_id", @@ -242,6 +247,7 @@ def get_recipient_info( "wildcard_mentions_notify", "followed_topic_push_notifications", "followed_topic_email_notifications", + "followed_topic_wildcard_mentions_notify", "user_profile_email_notifications", "user_profile_push_notifications", "user_profile_wildcard_mentions_notify", @@ -287,12 +293,14 @@ def get_recipient_info( followed_topic_push_user_ids = followed_topic_notification_recipients("push_notifications") if possible_wildcard_mention: - # We calculate `wildcard_mention_user_ids` only if there's a possible - # wildcard mention in the message. This is important so as to avoid - # unnecessarily sending huge user ID lists with thousands of elements - # to the event queue (which can happen because this setting is `True` - # by default for new users.) + # We calculate `wildcard_mention_user_ids` and `followed_topic_wildcard_mention_user_ids` + # only if there's a possible wildcard mention in the message. This is important so as + # to avoid unnecessarily sending huge user ID lists with thousands of elements to the + # event queue (which can happen because these settings are `True` by default for new users.) wildcard_mention_user_ids = notification_recipients("wildcard_mentions_notify") + followed_topic_wildcard_mention_user_ids = followed_topic_notification_recipients( + "wildcard_mentions_notify" + ) elif recipient.type == Recipient.HUDDLE: message_to_user_ids = get_huddle_user_ids(recipient) @@ -412,6 +420,7 @@ def get_recipient_info( wildcard_mention_user_ids=wildcard_mention_user_ids, followed_topic_push_user_ids=followed_topic_push_user_ids, followed_topic_email_user_ids=followed_topic_email_user_ids, + followed_topic_wildcard_mention_user_ids=followed_topic_wildcard_mention_user_ids, muted_sender_user_ids=muted_sender_user_ids, um_eligible_user_ids=um_eligible_user_ids, long_term_idle_user_ids=long_term_idle_user_ids, @@ -566,8 +575,10 @@ def build_message_send_dict( # code block). if rendering_result.mentions_wildcard: wildcard_mention_user_ids = info.wildcard_mention_user_ids + followed_topic_wildcard_mention_user_ids = info.followed_topic_wildcard_mention_user_ids else: wildcard_mention_user_ids = set() + followed_topic_wildcard_mention_user_ids = set() """ Once we have the actual list of mentioned ids from message @@ -604,6 +615,7 @@ def build_message_send_dict( service_bot_tuples=info.service_bot_tuples, all_bot_user_ids=info.all_bot_user_ids, wildcard_mention_user_ids=wildcard_mention_user_ids, + followed_topic_wildcard_mention_user_ids=followed_topic_wildcard_mention_user_ids, links_for_embed=links_for_embed, widget_content=widget_content_dict, limit_unread_user_ids=limit_unread_user_ids, @@ -902,6 +914,7 @@ def do_send_messages( wildcard_mention_user_ids=send_request.wildcard_mention_user_ids, followed_topic_push_user_ids=send_request.followed_topic_push_user_ids, followed_topic_email_user_ids=send_request.followed_topic_email_user_ids, + followed_topic_wildcard_mention_user_ids=send_request.followed_topic_wildcard_mention_user_ids, muted_sender_user_ids=send_request.muted_sender_user_ids, all_bot_user_ids=send_request.all_bot_user_ids, ) @@ -929,6 +942,9 @@ def do_send_messages( wildcard_mention_user_ids=list(send_request.wildcard_mention_user_ids), followed_topic_push_user_ids=list(send_request.followed_topic_push_user_ids), followed_topic_email_user_ids=list(send_request.followed_topic_email_user_ids), + followed_topic_wildcard_mention_user_ids=list( + send_request.followed_topic_wildcard_mention_user_ids + ), muted_sender_user_ids=list(send_request.muted_sender_user_ids), all_bot_user_ids=list(send_request.all_bot_user_ids), disable_external_notifications=send_request.disable_external_notifications, diff --git a/zerver/lib/email_notifications.py b/zerver/lib/email_notifications.py index 4fb9e55f37..1e2834f16f 100644 --- a/zerver/lib/email_notifications.py +++ b/zerver/lib/email_notifications.py @@ -453,11 +453,14 @@ def do_send_missedmessage_events_reply_in_zulip( ) context.update( - mention="mentioned" in unique_triggers or "wildcard_mentioned" in unique_triggers, + mention="mentioned" in unique_triggers + or "wildcard_mentioned" in unique_triggers + or "followed_topic_wildcard_mentioned" in unique_triggers, personal_mentioned=personal_mentioned, wildcard_mentioned="wildcard_mentioned" in unique_triggers, stream_email_notify="stream_email_notify" in unique_triggers, followed_topic_email_notify="followed_topic_email_notify" in unique_triggers, + followed_topic_wildcard_mentioned="followed_topic_wildcard_mentioned" in unique_triggers, mention_count=triggers.count("mentioned") + triggers.count("wildcard_mentioned"), mentioned_user_group_name=mentioned_user_group_name, ) diff --git a/zerver/lib/message.py b/zerver/lib/message.py index 55649ce364..976ca96a6b 100644 --- a/zerver/lib/message.py +++ b/zerver/lib/message.py @@ -167,6 +167,8 @@ class SendMessageRequest: service_bot_tuples: List[Tuple[int, int]] all_bot_user_ids: Set[int] wildcard_mention_user_ids: Set[int] + # IDs of users who have followed the topic the message is being sent to, and have the followed topic wildcard mentions notify setting ON. + followed_topic_wildcard_mention_user_ids: Set[int] links_for_embed: Set[str] widget_content: Optional[Dict[str, Any]] submessages: List[Dict[str, Any]] = field(default_factory=list) diff --git a/zerver/lib/notification_data.py b/zerver/lib/notification_data.py index cc9c934a70..a7432dc1f6 100644 --- a/zerver/lib/notification_data.py +++ b/zerver/lib/notification_data.py @@ -21,6 +21,8 @@ class UserMessageNotificationsData: stream_email_notify: bool followed_topic_push_notify: bool followed_topic_email_notify: bool + followed_topic_wildcard_mention_push_notify: bool + followed_topic_wildcard_mention_email_notify: bool sender_is_muted: bool disable_external_notifications: bool @@ -58,6 +60,7 @@ class UserMessageNotificationsData: wildcard_mention_user_ids: Set[int], followed_topic_push_user_ids: Set[int], followed_topic_email_user_ids: Set[int], + followed_topic_wildcard_mention_user_ids: Set[int], muted_sender_user_ids: Set[int], all_bot_user_ids: Set[int], ) -> "UserMessageNotificationsData": @@ -76,6 +79,8 @@ class UserMessageNotificationsData: stream_email_notify=False, followed_topic_push_notify=False, followed_topic_email_notify=False, + followed_topic_wildcard_mention_push_notify=False, + followed_topic_wildcard_mention_email_notify=False, sender_is_muted=False, disable_external_notifications=False, ) @@ -92,6 +97,11 @@ class UserMessageNotificationsData: and user_id not in pm_mention_email_disabled_user_ids and "wildcard_mentioned" in flags ) + followed_topic_wildcard_mention_email_notify = ( + user_id in followed_topic_wildcard_mention_user_ids + and user_id not in pm_mention_email_disabled_user_ids + and "wildcard_mentioned" in flags + ) pm_push_notify = user_id not in pm_mention_push_disabled_user_ids and private_message mention_push_notify = ( @@ -102,6 +112,11 @@ class UserMessageNotificationsData: and user_id not in pm_mention_push_disabled_user_ids and "wildcard_mentioned" in flags ) + followed_topic_wildcard_mention_push_notify = ( + user_id in followed_topic_wildcard_mention_user_ids + and user_id not in pm_mention_push_disabled_user_ids + and "wildcard_mentioned" in flags + ) return cls( user_id=user_id, pm_email_notify=pm_email_notify, @@ -115,6 +130,8 @@ class UserMessageNotificationsData: stream_email_notify=(user_id in stream_email_user_ids), followed_topic_push_notify=(user_id in followed_topic_push_user_ids), followed_topic_email_notify=(user_id in followed_topic_email_user_ids), + followed_topic_wildcard_mention_push_notify=followed_topic_wildcard_mention_push_notify, + followed_topic_wildcard_mention_email_notify=followed_topic_wildcard_mention_email_notify, sender_is_muted=(user_id in muted_sender_user_ids), disable_external_notifications=disable_external_notifications, ) @@ -160,6 +177,8 @@ class UserMessageNotificationsData: return NotificationTriggers.PRIVATE_MESSAGE elif self.mention_push_notify: return NotificationTriggers.MENTION + elif self.followed_topic_wildcard_mention_push_notify: + return NotificationTriggers.FOLLOWED_TOPIC_WILDCARD_MENTION elif self.wildcard_mention_push_notify: return NotificationTriggers.WILDCARD_MENTION elif self.followed_topic_push_notify: @@ -186,6 +205,8 @@ class UserMessageNotificationsData: return NotificationTriggers.PRIVATE_MESSAGE elif self.mention_email_notify: return NotificationTriggers.MENTION + elif self.followed_topic_wildcard_mention_email_notify: + return NotificationTriggers.FOLLOWED_TOPIC_WILDCARD_MENTION elif self.wildcard_mention_email_notify: return NotificationTriggers.WILDCARD_MENTION elif self.followed_topic_email_notify: diff --git a/zerver/lib/test_classes.py b/zerver/lib/test_classes.py index 735faffe69..8857444216 100644 --- a/zerver/lib/test_classes.py +++ b/zerver/lib/test_classes.py @@ -1731,6 +1731,12 @@ Output: stream_push_notify=kwargs.get("stream_push_notify", False), followed_topic_email_notify=kwargs.get("followed_topic_email_notify", False), followed_topic_push_notify=kwargs.get("followed_topic_push_notify", False), + followed_topic_wildcard_mention_email_notify=kwargs.get( + "followed_topic_wildcard_mention_email_notify", False + ), + followed_topic_wildcard_mention_push_notify=kwargs.get( + "followed_topic_wildcard_mention_push_notify", False + ), sender_is_muted=kwargs.get("sender_is_muted", False), disable_external_notifications=kwargs.get("disable_external_notifications", False), ) diff --git a/zerver/migrations/0331_scheduledmessagenotificationemail.py b/zerver/migrations/0331_scheduledmessagenotificationemail.py index 1051f54d75..45d9ed246b 100644 --- a/zerver/migrations/0331_scheduledmessagenotificationemail.py +++ b/zerver/migrations/0331_scheduledmessagenotificationemail.py @@ -29,6 +29,10 @@ class Migration(migrations.Migration): ("wildcard_mentioned", "Wildcard mention"), ("stream_email_notify", "Stream notifications enabled"), ("followed_topic_email_notify", "Followed topic notifications enabled"), + ( + "followed_topic_wildcard_mentioned", + "Followed topic wildcard mention", + ), ] ), ), diff --git a/zerver/models.py b/zerver/models.py index 6bb178f5cd..ec4374da19 100644 --- a/zerver/models.py +++ b/zerver/models.py @@ -1725,6 +1725,7 @@ class UserBaseSettings(models.Model): # Add new notification settings here. enable_followed_topic_email_notifications=bool, enable_followed_topic_push_notifications=bool, + enable_followed_topic_wildcard_mentions_notify=bool, ) notification_setting_types = { @@ -4287,6 +4288,7 @@ class NotificationTriggers: STREAM_EMAIL = "stream_email_notify" FOLLOWED_TOPIC_PUSH = "followed_topic_push_notify" FOLLOWED_TOPIC_EMAIL = "followed_topic_email_notify" + FOLLOWED_TOPIC_WILDCARD_MENTION = "followed_topic_wildcard_mentioned" class ScheduledMessageNotificationEmail(models.Model): @@ -4305,6 +4307,7 @@ class ScheduledMessageNotificationEmail(models.Model): (NotificationTriggers.WILDCARD_MENTION, "Wildcard mention"), (NotificationTriggers.STREAM_EMAIL, "Stream notifications enabled"), (NotificationTriggers.FOLLOWED_TOPIC_EMAIL, "Followed topic notifications enabled"), + (NotificationTriggers.FOLLOWED_TOPIC_WILDCARD_MENTION, "Followed topic wildcard mention"), ] trigger = models.TextField(choices=EMAIL_NOTIFICATION_TRIGGER_CHOICES) diff --git a/zerver/openapi/zulip.yaml b/zerver/openapi/zulip.yaml index ae64869ecb..ed9cc61b49 100644 --- a/zerver/openapi/zulip.yaml +++ b/zerver/openapi/zulip.yaml @@ -9827,6 +9827,16 @@ paths: schema: type: boolean example: true + - name: enable_followed_topic_wildcard_mentions_notify + in: query + description: | + Whether wildcard mentions (e.g., @**all**) in messages sent to followed topics + should send notifications like a personal mention. + + **Changes**: New in Zulip 8.0 (feature level 189). + schema: + type: boolean + example: true - name: desktop_icon_count_display in: query description: | @@ -11915,6 +11925,13 @@ paths: description: | Whether wildcard mentions (E.g. @**all**) should send notifications like a personal mention. + enable_followed_topic_wildcard_mentions_notify: + type: boolean + description: | + Whether wildcard mentions (e.g., @**all**) in messages sent to followed topics + should send notifications like a personal mention. + + **Changes**: New in Zulip 8.0 (feature level 189). desktop_icon_count_display: type: integer description: | @@ -13967,6 +13984,13 @@ paths: description: | Whether wildcard mentions (E.g. @**all**) should send notifications like a personal mention. + enable_followed_topic_wildcard_mentions_notify: + type: boolean + description: | + Whether wildcard mentions (e.g., @**all**) in messages sent to followed topics + should send notifications like a personal mention. + + **Changes**: New in Zulip 8.0 (feature level 189). desktop_icon_count_display: type: integer description: | @@ -15154,6 +15178,16 @@ paths: schema: type: boolean example: true + - name: enable_followed_topic_wildcard_mentions_notify + in: query + description: | + Whether wildcard mentions (e.g., @**all**) in messages sent to followed topics + should send notifications like a personal mention. + + **Changes**: New in Zulip 8.0 (feature level 189). + schema: + type: boolean + example: true - name: desktop_icon_count_display in: query description: | diff --git a/zerver/tests/test_event_queue.py b/zerver/tests/test_event_queue.py index 1d58cdfee0..0791bbb89e 100644 --- a/zerver/tests/test_event_queue.py +++ b/zerver/tests/test_event_queue.py @@ -839,6 +839,80 @@ class MissedMessageHookTest(ZulipTestCase): already_notified={"email_notified": True, "push_notified": False}, ) + def test_followed_topic_wildcard_mention_notify(self) -> None: + 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 + ) + + # By default, wildcard mentions in followed topics should send notifications, just like regular mentions. + do_set_user_topic_visibility_policy( + self.user_profile, + get_stream("Denmark", self.user_profile.realm), + "followed_topic_test", + visibility_policy=UserTopic.VisibilityPolicy.FOLLOWED, + ) + msg_id = self.send_stream_message( + self.iago, "Denmark", content="@**all** what's up?", topic_name="followed_topic_test" + ) + 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_once() + args_dict = mock_enqueue.call_args_list[0][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 + ) + 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 + ) + + # Now, disabling `enable_followed_topic_wildcard_mentions_notify` should result in no notifications. + do_change_user_setting( + self.user_profile, + "enable_followed_topic_wildcard_mentions_notify", + False, + acting_user=None, + ) + do_set_user_topic_visibility_policy( + self.user_profile, + get_stream("Denmark", self.user_profile.realm), + "followed_topic_test", + visibility_policy=UserTopic.VisibilityPolicy.FOLLOWED, + ) + msg_id = self.send_stream_message( + self.iago, "Denmark", content="@**all** what's up?", topic_name="followed_topic_test" + ) + 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_once() + args_dict = mock_enqueue.call_args_list[0][1] + + self.assert_maybe_enqueue_notifications_call_args( + args_dict=args_dict, + message_id=msg_id, + user_id=self.user_profile.id, + already_notified={"email_notified": False, "push_notified": False}, + ) + def test_muted_sender(self) -> None: do_mute_user(self.user_profile, self.iago) msg_id = self.send_personal_message(self.iago, self.user_profile) diff --git a/zerver/tests/test_notification_data.py b/zerver/tests/test_notification_data.py index e90728baff..4f2d5cebaf 100644 --- a/zerver/tests/test_notification_data.py +++ b/zerver/tests/test_notification_data.py @@ -70,6 +70,16 @@ class TestNotificationData(ZulipTestCase): ) self.assertTrue(user_data.is_push_notifiable(acting_user_id=acting_user_id, idle=True)) + # Followed Topic wildcard mention + user_data = self.create_user_notifications_data_object( + user_id=user_id, followed_topic_wildcard_mention_push_notify=True + ) + self.assertEqual( + user_data.get_push_notification_trigger(acting_user_id=acting_user_id, idle=True), + "followed_topic_wildcard_mentioned", + ) + self.assertTrue(user_data.is_push_notifiable(acting_user_id=acting_user_id, idle=True)) + # Now, test the `online_push_enabled` property # Test no notifications when not idle user_data = self.create_user_notifications_data_object(user_id=user_id, pm_push_notify=True) @@ -202,6 +212,16 @@ class TestNotificationData(ZulipTestCase): ) self.assertTrue(user_data.is_email_notifiable(acting_user_id=acting_user_id, idle=True)) + # Followed Topic wildcard mention + user_data = self.create_user_notifications_data_object( + user_id=user_id, followed_topic_wildcard_mention_email_notify=True + ) + self.assertEqual( + user_data.get_email_notification_trigger(acting_user_id=acting_user_id, idle=True), + "followed_topic_wildcard_mentioned", + ) + self.assertTrue(user_data.is_email_notifiable(acting_user_id=acting_user_id, idle=True)) + # Test no notifications when not idle user_data = self.create_user_notifications_data_object( user_id=user_id, pm_email_notify=True @@ -289,6 +309,7 @@ class TestNotificationData(ZulipTestCase): wildcard_mention_user_ids=set(), followed_topic_email_user_ids=set(), followed_topic_push_user_ids=set(), + followed_topic_wildcard_mention_user_ids=set(), ) self.assertEqual(user_data.is_notifiable(acting_user_id=1000, idle=True), notifiable) diff --git a/zerver/tests/test_users.py b/zerver/tests/test_users.py index 0ff7e9925b..d75f714f09 100644 --- a/zerver/tests/test_users.py +++ b/zerver/tests/test_users.py @@ -1765,6 +1765,7 @@ class RecipientInfoTest(ZulipTestCase): wildcard_mention_user_ids=set(), followed_topic_push_user_ids=set(), followed_topic_email_user_ids=set(), + followed_topic_wildcard_mention_user_ids=set(), muted_sender_user_ids=set(), um_eligible_user_ids=all_user_ids, long_term_idle_user_ids=set(), @@ -1981,8 +1982,9 @@ class RecipientInfoTest(ZulipTestCase): self.assertEqual(info.default_bot_user_ids, {normal_bot.id}) self.assertEqual(info.all_bot_user_ids, {normal_bot.id, service_bot.id}) - # Now Hamlet follows the topic with the 'followed_topic_email_notifications' - # and 'followed_topic_push_notifications' global settings enabled by default. + # Now Hamlet follows the topic with the 'followed_topic_email_notifications', + # 'followed_topic_push_notifications' and 'followed_topic_wildcard_mention_notify' + # global settings enabled by default. do_set_user_topic_visibility_policy( hamlet, stream, @@ -1998,6 +2000,7 @@ class RecipientInfoTest(ZulipTestCase): ) self.assertEqual(info.followed_topic_email_user_ids, {hamlet.id}) self.assertEqual(info.followed_topic_push_user_ids, {hamlet.id}) + self.assertEqual(info.followed_topic_wildcard_mention_user_ids, {hamlet.id}) # Omit Hamlet from followed_topic_email_user_ids do_change_user_setting( @@ -2013,6 +2016,13 @@ class RecipientInfoTest(ZulipTestCase): False, acting_user=None, ) + # Omit Hamlet from followed_topic_wildcard_mention_user_ids + do_change_user_setting( + hamlet, + "enable_followed_topic_wildcard_mentions_notify", + False, + acting_user=None, + ) info = get_recipient_info( realm_id=realm.id, @@ -2022,6 +2032,7 @@ class RecipientInfoTest(ZulipTestCase): ) self.assertEqual(info.followed_topic_email_user_ids, set()) self.assertEqual(info.followed_topic_push_user_ids, set()) + self.assertEqual(info.followed_topic_wildcard_mention_user_ids, set()) def test_get_recipient_info_invalid_recipient_type(self) -> None: hamlet = self.example_user("hamlet") diff --git a/zerver/tornado/event_queue.py b/zerver/tornado/event_queue.py index 16916c1c5e..84bb0ccdac 100644 --- a/zerver/tornado/event_queue.py +++ b/zerver/tornado/event_queue.py @@ -782,6 +782,12 @@ def missedmessage_hook( stream_email_notify=internal_data.get("stream_email_notify", False), followed_topic_push_notify=internal_data.get("followed_topic_push_notify", False), followed_topic_email_notify=internal_data.get("followed_topic_email_notify", False), + followed_topic_wildcard_mention_push_notify=internal_data.get( + "followed_topic_wildcard_mention_push_notify", False + ), + followed_topic_wildcard_mention_email_notify=internal_data.get( + "followed_topic_wildcard_mention_email_notify", False + ), # Since one is by definition idle, we don't need to check online_push_enabled online_push_enabled=False, disable_external_notifications=internal_data.get( @@ -937,6 +943,9 @@ def process_message_event( wildcard_mention_user_ids = set(event_template.get("wildcard_mention_user_ids", [])) followed_topic_push_user_ids = set(event_template.get("followed_topic_push_user_ids", [])) followed_topic_email_user_ids = set(event_template.get("followed_topic_email_user_ids", [])) + followed_topic_wildcard_mention_user_ids = set( + event_template.get("followed_topic_wildcard_mention_user_ids", []) + ) muted_sender_user_ids = set(event_template.get("muted_sender_user_ids", [])) all_bot_user_ids = set(event_template.get("all_bot_user_ids", [])) disable_external_notifications = event_template.get("disable_external_notifications", False) @@ -989,6 +998,7 @@ def process_message_event( wildcard_mention_user_ids=wildcard_mention_user_ids, followed_topic_push_user_ids=followed_topic_push_user_ids, followed_topic_email_user_ids=followed_topic_email_user_ids, + followed_topic_wildcard_mention_user_ids=followed_topic_wildcard_mention_user_ids, muted_sender_user_ids=muted_sender_user_ids, all_bot_user_ids=all_bot_user_ids, ) @@ -1142,6 +1152,9 @@ def process_message_update_event( wildcard_mention_user_ids = set(event_template.pop("wildcard_mention_user_ids", [])) followed_topic_push_user_ids = set(event_template.pop("followed_topic_push_user_ids", [])) followed_topic_email_user_ids = set(event_template.pop("followed_topic_email_user_ids", [])) + followed_topic_wildcard_mention_user_ids = set( + event_template.pop("followed_topic_wildcard_mention_user_ids", []) + ) muted_sender_user_ids = set(event_template.pop("muted_sender_user_ids", [])) all_bot_user_ids = set(event_template.pop("all_bot_user_ids", [])) disable_external_notifications = event_template.pop("disable_external_notifications", False) @@ -1204,6 +1217,7 @@ def process_message_update_event( wildcard_mention_user_ids=wildcard_mention_user_ids, followed_topic_push_user_ids=followed_topic_push_user_ids, followed_topic_email_user_ids=followed_topic_email_user_ids, + followed_topic_wildcard_mention_user_ids=followed_topic_wildcard_mention_user_ids, muted_sender_user_ids=muted_sender_user_ids, all_bot_user_ids=all_bot_user_ids, ) diff --git a/zerver/views/realm.py b/zerver/views/realm.py index 20327d8f1a..56ca235ea5 100644 --- a/zerver/views/realm.py +++ b/zerver/views/realm.py @@ -432,6 +432,9 @@ def update_realm_user_settings_defaults( enable_followed_topic_push_notifications: Optional[bool] = REQ( json_validator=check_bool, default=None ), + enable_followed_topic_wildcard_mentions_notify: Optional[bool] = REQ( + json_validator=check_bool, default=None + ), notification_sound: Optional[str] = REQ(default=None), enable_desktop_notifications: Optional[bool] = REQ(json_validator=check_bool, default=None), enable_sounds: Optional[bool] = REQ(json_validator=check_bool, default=None), diff --git a/zerver/views/user_settings.py b/zerver/views/user_settings.py index 80eceeaa94..bb7896495d 100644 --- a/zerver/views/user_settings.py +++ b/zerver/views/user_settings.py @@ -199,6 +199,9 @@ def json_change_settings( enable_followed_topic_push_notifications: Optional[bool] = REQ( json_validator=check_bool, default=None ), + enable_followed_topic_wildcard_mentions_notify: Optional[bool] = REQ( + json_validator=check_bool, default=None + ), notification_sound: Optional[str] = REQ(default=None), enable_desktop_notifications: Optional[bool] = REQ(json_validator=check_bool, default=None), enable_sounds: Optional[bool] = REQ(json_validator=check_bool, default=None),