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),