notification_data: Add methods to determine notifiability.

We will later consistently use these functions to check for notifiable
messages in the message send and event_queue code.

We have these functions accept the `sender_id` so that we can avoid the
`private_message = message["type"] == "private" and user_id != sender_id`
wizardy.
This commit is contained in:
Abhijeet Prasad Bodas
2021-06-15 18:00:51 +05:30
committed by Tim Abbott
parent ed58393079
commit 8182632d7e
3 changed files with 209 additions and 0 deletions

View File

@@ -18,3 +18,46 @@ class UserMessageNotificationsData:
assert "mentioned" in self.flags
if self.wildcard_mention_notify:
assert "wildcard_mentioned" in self.flags
# TODO: The following functions should also look at the `enable_offline_push_notifications` and
# `enable_offline_email_notifications` settings (for PMs and mentions), but currently they
# don't.
def is_notifiable(self, private_message: bool, sender_id: int, idle: bool) -> bool:
return self.is_email_notifiable(
private_message, sender_id, idle
) or self.is_push_notifiable(private_message, sender_id, idle)
def is_push_notifiable(self, private_message: bool, sender_id: int, idle: bool) -> bool:
if not idle and not self.online_push_enabled:
return False
if self.id == sender_id:
return False
if self.sender_is_muted:
return False
return (
private_message
or self.mentioned
or self.wildcard_mention_notify
or self.stream_push_notify
)
def is_email_notifiable(self, private_message: bool, sender_id: int, idle: bool) -> bool:
if not idle:
return False
if self.id == sender_id:
return False
if self.sender_is_muted:
return False
return (
private_message
or self.mentioned
or self.wildcard_mention_notify
or self.stream_email_notify
)

View File

@@ -55,6 +55,7 @@ from zerver.lib.actions import (
)
from zerver.lib.cache import bounce_key_prefix_for_testing
from zerver.lib.initial_password import initial_password
from zerver.lib.notification_data import UserMessageNotificationsData
from zerver.lib.rate_limiter import bounce_redis_key_prefix_for_testing
from zerver.lib.sessions import get_session_dict_user
from zerver.lib.stream_subscription import get_stream_subscriptions_for_user
@@ -1322,6 +1323,18 @@ Output:
self.assert_length(lst, expected_num_events)
def create_user_notifications_data_object(self, **kwargs: Any) -> UserMessageNotificationsData:
return UserMessageNotificationsData(
id=kwargs.get("id", self.example_user("hamlet").id),
flags=kwargs.get("flags", []),
mentioned=kwargs.get("mentioned", False),
online_push_enabled=kwargs.get("online_push_enabled", False),
stream_email_notify=kwargs.get("stream_email_notify", False),
stream_push_notify=kwargs.get("stream_push_notify", False),
wildcard_mention_notify=kwargs.get("wildcard_mention_notify", False),
sender_is_muted=kwargs.get("sender_is_muted", False),
)
def get_maybe_enqueue_notifications_parameters(self, **kwargs: Any) -> Dict[str, Any]:
"""
Returns a dictionary with the passed parameters, after filling up the

View File

@@ -0,0 +1,153 @@
from zerver.lib.test_classes import ZulipTestCase
class TestNotificationData(ZulipTestCase):
def test_is_push_notifiable(self) -> None:
sender_id = self.example_user("cordelia").id
# Boring case
user_data = self.create_user_notifications_data_object()
self.assertFalse(
user_data.is_push_notifiable(private_message=False, sender_id=sender_id, idle=True)
)
# Notifiable cases for PMs, mentions, stream notifications
user_data = self.create_user_notifications_data_object()
self.assertTrue(
user_data.is_push_notifiable(private_message=True, sender_id=sender_id, idle=True)
)
user_data = self.create_user_notifications_data_object(flags=["mentioned"], mentioned=True)
self.assertTrue(
user_data.is_push_notifiable(private_message=False, sender_id=sender_id, idle=True)
)
user_data = self.create_user_notifications_data_object(
flags=["wildcard_mentioned"], wildcard_mention_notify=True
)
self.assertTrue(
user_data.is_push_notifiable(private_message=False, sender_id=sender_id, idle=True)
)
user_data = self.create_user_notifications_data_object(stream_push_notify=True)
self.assertTrue(
user_data.is_push_notifiable(private_message=False, sender_id=sender_id, idle=True)
)
# Now, test the `online_push_enabled` property
# Test no notifications when not idle
user_data = self.create_user_notifications_data_object()
self.assertFalse(
user_data.is_push_notifiable(private_message=True, sender_id=sender_id, idle=False)
)
# Test notifications are sent when not idle but `online_push_enabled = True`
user_data = self.create_user_notifications_data_object(online_push_enabled=True)
self.assertTrue(
user_data.is_push_notifiable(private_message=True, sender_id=sender_id, idle=False)
)
# The following are hypothetical cases, since a private message can never have `stream_push_notify = True`.
# We just want to test the early (False) return patterns in these special cases:
# Message sender is muted.
user_data = self.create_user_notifications_data_object(
sender_is_muted=True,
flags=["mentioned", "wildcard_mentioned"],
wildcard_mention_notify=True,
mentioned=True,
stream_email_notify=True,
stream_push_notify=True,
)
self.assertFalse(
user_data.is_push_notifiable(private_message=True, sender_id=sender_id, idle=True)
)
# Message sender is the user the object corresponds to.
user_data = self.create_user_notifications_data_object(
id=sender_id,
sender_is_muted=False,
flags=["mentioned", "wildcard_mentioned"],
wildcard_mention_notify=True,
mentioned=True,
stream_email_notify=True,
stream_push_notify=True,
)
self.assertFalse(
user_data.is_push_notifiable(private_message=True, sender_id=sender_id, idle=True)
)
def test_is_email_notifiable(self) -> None:
sender_id = self.example_user("cordelia").id
# Boring case
user_data = self.create_user_notifications_data_object()
self.assertFalse(
user_data.is_email_notifiable(private_message=False, sender_id=sender_id, idle=True)
)
# Notifiable cases for PMs, mentions, stream notifications
user_data = self.create_user_notifications_data_object()
self.assertTrue(
user_data.is_email_notifiable(private_message=True, sender_id=sender_id, idle=True)
)
user_data = self.create_user_notifications_data_object(flags=["mentioned"], mentioned=True)
self.assertTrue(
user_data.is_email_notifiable(private_message=False, sender_id=sender_id, idle=True)
)
user_data = self.create_user_notifications_data_object(
flags=["wildcard_mentioned"], wildcard_mention_notify=True
)
self.assertTrue(
user_data.is_email_notifiable(private_message=False, sender_id=sender_id, idle=True)
)
user_data = self.create_user_notifications_data_object(stream_email_notify=True)
self.assertTrue(
user_data.is_email_notifiable(private_message=False, sender_id=sender_id, idle=True)
)
# Test no notifications when not idle
user_data = self.create_user_notifications_data_object()
self.assertFalse(
user_data.is_email_notifiable(private_message=True, sender_id=sender_id, idle=False)
)
# The following are hypothetical cases, since a private message can never have `stream_email_notify = True`.
# We just want to test the early (False) return patterns in these special cases:
# Message sender is muted.
user_data = self.create_user_notifications_data_object(
sender_is_muted=True,
flags=["mentioned", "wildcard_mentioned"],
wildcard_mention_notify=True,
mentioned=True,
stream_email_notify=True,
stream_push_notify=True,
)
self.assertFalse(
user_data.is_email_notifiable(private_message=True, sender_id=sender_id, idle=True)
)
# Message sender is the user the object corresponds to.
user_data = self.create_user_notifications_data_object(
id=sender_id,
sender_is_muted=False,
flags=["mentioned", "wildcard_mentioned"],
wildcard_mention_notify=True,
mentioned=True,
stream_email_notify=True,
stream_push_notify=True,
)
self.assertFalse(
user_data.is_email_notifiable(private_message=True, sender_id=sender_id, idle=True)
)
def test_is_notifiable(self) -> None:
# This is just for coverage purposes. We've already tested all scenarios above,
# and `is_notifiable` is a simple OR of the email and push functions.
sender_id = self.example_user("cordelia").id
user_data = self.create_user_notifications_data_object()
self.assertTrue(
user_data.is_notifiable(private_message=True, sender_id=sender_id, idle=True)
)