mirror of
https://github.com/zulip/zulip.git
synced 2025-11-05 06:23:38 +00:00
This commit allows clients to register client_gravatar=True, and then we recognize that flag for message events. If the flag is True, we will not calculate gravatar URLs and let the clients do it themselves. (Clients can calculate gravatar URLs based on emails with just a little bit of code.)
248 lines
13 KiB
Python
248 lines
13 KiB
Python
import mock
|
|
import ujson
|
|
|
|
from django.http import HttpRequest, HttpResponse
|
|
from typing import Any, Callable, Dict, Tuple
|
|
|
|
from zerver.lib.actions import do_mute_topic
|
|
from zerver.lib.test_classes import ZulipTestCase
|
|
from zerver.lib.test_helpers import POSTRequestMock
|
|
from zerver.models import Recipient, Subscription, UserProfile, get_stream
|
|
from zerver.tornado.event_queue import maybe_enqueue_notifications, \
|
|
get_client_descriptor, missedmessage_hook
|
|
from zerver.tornado.views import get_events_backend
|
|
|
|
class MissedMessageNotificationsTest(ZulipTestCase):
|
|
"""Tests the logic for when missed-message notifications
|
|
should be triggered, based on user settings"""
|
|
def check_will_notify(self, *args, **kwargs):
|
|
# type: (*Any, **Any) -> Tuple[str, str]
|
|
email_notice = None
|
|
mobile_notice = None
|
|
with mock.patch("zerver.tornado.event_queue.queue_json_publish") as mock_queue_publish:
|
|
notified = maybe_enqueue_notifications(*args, **kwargs)
|
|
for entry in mock_queue_publish.call_args_list:
|
|
args = entry[0]
|
|
if args[0] == "missedmessage_mobile_notifications":
|
|
mobile_notice = args[1]
|
|
if args[0] == "missedmessage_emails":
|
|
email_notice = args[1]
|
|
|
|
# Now verify the return value matches the queue actions
|
|
if email_notice:
|
|
self.assertTrue(notified['email_notified'])
|
|
else:
|
|
self.assertFalse(notified.get('email_notified', False))
|
|
if mobile_notice:
|
|
self.assertTrue(notified['push_notified'])
|
|
else:
|
|
self.assertFalse(notified.get('push_notified', False))
|
|
return email_notice, mobile_notice
|
|
|
|
def test_enqueue_notifications(self):
|
|
# type: () -> None
|
|
user_profile = self.example_user("hamlet")
|
|
message_id = 32
|
|
|
|
# Boring message doesn't send a notice
|
|
email_notice, mobile_notice = self.check_will_notify(
|
|
user_profile.id, message_id, private_message=False,
|
|
mentioned=False, stream_push_notify=False, stream_name=None,
|
|
always_push_notify=False, idle=True, already_notified={})
|
|
self.assertTrue(email_notice is None)
|
|
self.assertTrue(mobile_notice is None)
|
|
|
|
# Private message sends a notice
|
|
email_notice, mobile_notice = self.check_will_notify(
|
|
user_profile.id, message_id, private_message=True,
|
|
mentioned=False, stream_push_notify=False, stream_name=None,
|
|
always_push_notify=False, idle=True, already_notified={})
|
|
self.assertTrue(email_notice is not None)
|
|
self.assertTrue(mobile_notice is not None)
|
|
|
|
# Private message won't double-send either notice if we've
|
|
# already sent notices before.
|
|
email_notice, mobile_notice = self.check_will_notify(
|
|
user_profile.id, message_id, private_message=True,
|
|
mentioned=False, stream_push_notify=False, stream_name=None,
|
|
always_push_notify=False, idle=True, already_notified={
|
|
'push_notified': True,
|
|
'email_notified': False,
|
|
})
|
|
self.assertTrue(email_notice is not None)
|
|
self.assertTrue(mobile_notice is None)
|
|
|
|
email_notice, mobile_notice = self.check_will_notify(
|
|
user_profile.id, message_id, private_message=True,
|
|
mentioned=False, stream_push_notify=False, stream_name=None,
|
|
always_push_notify=False, idle=True, already_notified={
|
|
'push_notified': False,
|
|
'email_notified': True,
|
|
})
|
|
self.assertTrue(email_notice is None)
|
|
self.assertTrue(mobile_notice is not None)
|
|
|
|
# Mention sends a notice
|
|
email_notice, mobile_notice = self.check_will_notify(
|
|
user_profile.id, message_id, private_message=False,
|
|
mentioned=True, stream_push_notify=False, stream_name=None,
|
|
always_push_notify=False, idle=True, already_notified={})
|
|
self.assertTrue(email_notice is not None)
|
|
self.assertTrue(mobile_notice is not None)
|
|
|
|
# stream_push_notify pushes but doesn't email
|
|
email_notice, mobile_notice = self.check_will_notify(
|
|
user_profile.id, message_id, private_message=False,
|
|
mentioned=False, stream_push_notify=True, stream_name="Denmark",
|
|
always_push_notify=False, idle=True, already_notified={})
|
|
self.assertTrue(email_notice is None)
|
|
self.assertTrue(mobile_notice is not None)
|
|
|
|
# Private message doesn't send a notice if not idle
|
|
email_notice, mobile_notice = self.check_will_notify(
|
|
user_profile.id, message_id, private_message=True,
|
|
mentioned=False, stream_push_notify=False, stream_name=None,
|
|
always_push_notify=False, idle=False, already_notified={})
|
|
self.assertTrue(email_notice is None)
|
|
self.assertTrue(mobile_notice is None)
|
|
|
|
# Private message sends push but not email if not idle but always_push_notify
|
|
email_notice, mobile_notice = self.check_will_notify(
|
|
user_profile.id, message_id, private_message=True,
|
|
mentioned=False, stream_push_notify=False, stream_name=None,
|
|
always_push_notify=True, idle=False, already_notified={})
|
|
self.assertTrue(email_notice is None)
|
|
self.assertTrue(mobile_notice is not None)
|
|
|
|
def tornado_call(self, view_func, user_profile, post_data):
|
|
# type: (Callable[[HttpRequest, UserProfile], HttpResponse], UserProfile, Dict[str, Any]) -> HttpResponse
|
|
request = POSTRequestMock(post_data, user_profile)
|
|
return view_func(request, user_profile)
|
|
|
|
def test_end_to_end_missedmessage_hook(self):
|
|
# type: () -> None
|
|
"""Tests what arguments missedmessage_hook passes into maybe_enqueue_notifications.
|
|
Combined with the previous test, this ensures that the missedmessage_hook is correct"""
|
|
user_profile = self.example_user('hamlet')
|
|
email = user_profile.email
|
|
self.login(email)
|
|
|
|
result = self.tornado_call(get_events_backend, user_profile,
|
|
{"apply_markdown": ujson.dumps(True),
|
|
"client_gravatar": ujson.dumps(True),
|
|
"event_types": ujson.dumps(["message"]),
|
|
"user_client": "website",
|
|
"dont_block": ujson.dumps(True),
|
|
})
|
|
self.assert_json_success(result)
|
|
queue_id = ujson.loads(result.content)["queue_id"]
|
|
client_descriptor = get_client_descriptor(queue_id)
|
|
|
|
with mock.patch("zerver.tornado.event_queue.maybe_enqueue_notifications") as mock_enqueue:
|
|
# To test the missed_message hook, we first need to send a message
|
|
msg_id = self.send_stream_message(self.example_email("iago"), "Denmark")
|
|
|
|
# Verify that nothing happens if you call it as not the
|
|
# "last client descriptor", in which case the function
|
|
# short-circuits, since the `missedmessage_hook` handler
|
|
# for garbage-collection is only for the user's last queue.
|
|
missedmessage_hook(user_profile.id, client_descriptor, False)
|
|
mock_enqueue.assert_not_called()
|
|
|
|
# Now verify that we called the appropriate enqueue function
|
|
missedmessage_hook(user_profile.id, client_descriptor, True)
|
|
mock_enqueue.assert_called_once()
|
|
args_list = mock_enqueue.call_args_list[0][0]
|
|
|
|
self.assertEqual(args_list, (user_profile.id, msg_id, False, False, False,
|
|
"Denmark", False, True,
|
|
{'email_notified': False, 'push_notified': False}))
|
|
|
|
# Clear the event queue, before repeating with a private message
|
|
client_descriptor.event_queue.pop()
|
|
self.assertTrue(client_descriptor.event_queue.empty())
|
|
msg_id = self.send_personal_message(self.example_email("iago"), email)
|
|
with mock.patch("zerver.tornado.event_queue.maybe_enqueue_notifications") as mock_enqueue:
|
|
missedmessage_hook(user_profile.id, client_descriptor, True)
|
|
mock_enqueue.assert_called_once()
|
|
args_list = mock_enqueue.call_args_list[0][0]
|
|
|
|
self.assertEqual(args_list, (user_profile.id, msg_id, True, False,
|
|
False, None, False, True,
|
|
{'email_notified': True, 'push_notified': True}))
|
|
|
|
# Clear the event queue, now repeat with a mention
|
|
client_descriptor.event_queue.pop()
|
|
self.assertTrue(client_descriptor.event_queue.empty())
|
|
msg_id = self.send_stream_message(self.example_email("iago"), "Denmark",
|
|
content="@**King Hamlet** what's up?")
|
|
with mock.patch("zerver.tornado.event_queue.maybe_enqueue_notifications") as mock_enqueue:
|
|
# Clear the event queue, before repeating with a private message
|
|
missedmessage_hook(user_profile.id, client_descriptor, True)
|
|
mock_enqueue.assert_called_once()
|
|
args_list = mock_enqueue.call_args_list[0][0]
|
|
|
|
self.assertEqual(args_list, (user_profile.id, msg_id, False, True,
|
|
False, "Denmark", False, True,
|
|
{'email_notified': True, 'push_notified': True}))
|
|
|
|
# Clear the event queue, now repeat with stream message with stream_push_notify
|
|
stream = get_stream("Denmark", user_profile.realm)
|
|
sub = Subscription.objects.get(user_profile=user_profile, recipient__type=Recipient.STREAM,
|
|
recipient__type_id=stream.id)
|
|
sub.push_notifications = True
|
|
sub.save()
|
|
client_descriptor.event_queue.pop()
|
|
self.assertTrue(client_descriptor.event_queue.empty())
|
|
msg_id = self.send_stream_message(self.example_email("iago"), "Denmark",
|
|
content="what's up everyone?")
|
|
with mock.patch("zerver.tornado.event_queue.maybe_enqueue_notifications") as mock_enqueue:
|
|
# Clear the event queue, before repeating with a private message
|
|
missedmessage_hook(user_profile.id, client_descriptor, True)
|
|
mock_enqueue.assert_called_once()
|
|
args_list = mock_enqueue.call_args_list[0][0]
|
|
|
|
self.assertEqual(args_list, (user_profile.id, msg_id, False, False,
|
|
True, "Denmark", False, True,
|
|
{'email_notified': False, 'push_notified': False}))
|
|
|
|
# Clear the event queue, now repeat with stream message with stream_push_notify
|
|
# on a muted topic, which we should not push notify for
|
|
client_descriptor.event_queue.pop()
|
|
self.assertTrue(client_descriptor.event_queue.empty())
|
|
do_mute_topic(user_profile, stream, sub.recipient, "mutingtest")
|
|
msg_id = self.send_stream_message(self.example_email("iago"), "Denmark",
|
|
content="what's up everyone?", topic_name="mutingtest")
|
|
with mock.patch("zerver.tornado.event_queue.maybe_enqueue_notifications") as mock_enqueue:
|
|
# Clear the event queue, before repeating with a private message
|
|
missedmessage_hook(user_profile.id, client_descriptor, True)
|
|
mock_enqueue.assert_called_once()
|
|
args_list = mock_enqueue.call_args_list[0][0]
|
|
|
|
self.assertEqual(args_list, (user_profile.id, msg_id, False, False,
|
|
False, "Denmark", False, True,
|
|
{'email_notified': False, 'push_notified': False}))
|
|
|
|
# Clear the event queue, now repeat with stream message with stream_push_notify
|
|
# on a muted stream, which we should not push notify for
|
|
client_descriptor.event_queue.pop()
|
|
self.assertTrue(client_descriptor.event_queue.empty())
|
|
sub.in_home_view = False
|
|
sub.save()
|
|
msg_id = self.send_stream_message(self.example_email("iago"), "Denmark",
|
|
content="what's up everyone?")
|
|
with mock.patch("zerver.tornado.event_queue.maybe_enqueue_notifications") as mock_enqueue:
|
|
# Clear the event queue, before repeating with a private message
|
|
missedmessage_hook(user_profile.id, client_descriptor, True)
|
|
mock_enqueue.assert_called_once()
|
|
args_list = mock_enqueue.call_args_list[0][0]
|
|
|
|
self.assertEqual(args_list, (user_profile.id, msg_id, False, False,
|
|
False, "Denmark", False, True,
|
|
{'email_notified': False, 'push_notified': False}))
|
|
|
|
# Clean up the state we just changed (not necessary unless we add more test code below)
|
|
sub.push_notifications = True
|
|
sub.in_home_view = True
|
|
sub.save()
|