def mute_topic(user_profile: UserProfile, stream_name: str, topic_name: str) -> HttpResponse: (stream, recipient, sub) = access_stream_by_name(user_profile, stream_name) if topic_is_muted(user_profile, stream.id, topic_name): return json_error(_("Topic already muted")) do_mute_topic(user_profile, stream, recipient, topic_name) return json_success()
def mute_topic(user_profile: UserProfile, stream_id: Optional[int], stream_name: Optional[str], topic_name: str) -> HttpResponse: if stream_name is not None: (stream, recipient, sub) = access_stream_by_name(user_profile, stream_name) else: assert stream_id is not None (stream, recipient, sub) = access_stream_by_id(user_profile, stream_id) if topic_is_muted(user_profile, stream.id, topic_name): return json_error(_("Topic already muted")) do_mute_topic(user_profile, stream, recipient, topic_name) return json_success()
def mute_topic( user_profile: UserProfile, stream_id: Optional[int], stream_name: Optional[str], topic_name: str, date_muted: datetime.datetime, ) -> HttpResponse: if stream_name is not None: (stream, sub) = access_stream_by_name(user_profile, stream_name) else: assert stream_id is not None (stream, sub) = access_stream_by_id(user_profile, stream_id) if topic_is_muted(user_profile, stream.id, topic_name): raise JsonableError(_("Topic already muted")) do_mute_topic(user_profile, stream, topic_name, date_muted) return json_success()
def mute_topic( user_profile: UserProfile, stream_id: Optional[int], stream_name: Optional[str], topic_name: str, date_muted: datetime.datetime, ) -> None: if stream_name is not None: (stream, sub) = access_stream_by_name(user_profile, stream_name) else: assert stream_id is not None (stream, sub) = access_stream_by_id(user_profile, stream_id) if topic_is_muted(user_profile, stream.id, topic_name): raise JsonableError(_("Topic already muted")) try: do_mute_topic(user_profile, stream, topic_name, date_muted) except IntegrityError: raise JsonableError(_("Topic already muted"))
def test_end_to_end_missedmessage_hook(self) -> 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) def change_subscription_properties( user_profile: UserProfile, stream: Stream, sub: Subscription, properties: Dict[str, bool]) -> None: for property_name, value in properties.items(): do_change_subscription_property(user_profile, sub, stream, property_name, value) result = self.tornado_call( get_events, 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, 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, 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, False, "Denmark", False, True, { 'email_notified': True, 'push_notified': True })) stream = get_stream("Denmark", user_profile.realm) sub = Subscription.objects.get(user_profile=user_profile, recipient__type=Recipient.STREAM, recipient__type_id=stream.id) # Clear the event queue, now repeat with stream message with stream_push_notify change_subscription_properties(user_profile, stream, sub, {'push_notifications': True}) 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, False, "Denmark", False, True, { 'email_notified': False, 'push_notified': False })) # Clear the event queue, now repeat with stream message with stream_email_notify change_subscription_properties(user_profile, stream, sub, { 'push_notifications': False, 'email_notifications': True }) 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, 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 change_subscription_properties(user_profile, stream, sub, { 'push_notifications': True, 'email_notifications': False }) 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, False, "Denmark", False, True, { 'email_notified': False, 'push_notified': False })) # Clear the event queue, now repeat with stream message with stream_email_notify # on a muted stream, which we should not email notify for change_subscription_properties(user_profile, stream, sub, { 'push_notifications': False, 'email_notifications': True }) client_descriptor.event_queue.pop() self.assertTrue(client_descriptor.event_queue.empty()) change_subscription_properties(user_profile, stream, sub, {'in_home_view': False}) 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, 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) change_subscription_properties(user_profile, stream, sub, { 'push_notifications': True, 'in_home_view': True })
def test_end_to_end_missedmessage_hook(self) -> 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") cordelia = self.example_user("cordelia") user_profile.enable_online_push_notifications = False user_profile.save() iago = self.example_user("iago") # Fetch the Denmark stream for testing stream = get_stream("Denmark", user_profile.realm) sub = Subscription.objects.get( user_profile=user_profile, recipient__type=Recipient.STREAM, recipient__type_id=stream.id, ) self.login_user(user_profile) def change_subscription_properties( user_profile: UserProfile, stream: Stream, sub: Subscription, properties: Dict[str, bool], ) -> None: for property_name, value in properties.items(): do_change_subscription_property( user_profile, sub, stream, property_name, value, acting_user=None ) def allocate_event_queue() -> ClientDescriptor: result = self.tornado_call( get_events, user_profile, { "apply_markdown": orjson.dumps(True).decode(), "client_gravatar": orjson.dumps(True).decode(), "event_types": orjson.dumps(["message"]).decode(), "user_client": "website", "dont_block": orjson.dumps(True).decode(), }, ) self.assert_json_success(result) queue_id = orjson.loads(result.content)["queue_id"] return get_client_descriptor(queue_id) def destroy_event_queue(queue_id: str) -> None: result = self.tornado_call(cleanup_event_queue, user_profile, {"queue_id": queue_id}) self.assert_json_success(result) def assert_maybe_enqueue_notifications_call_args( args_dict: Collection[Any], message_id: int, **kwargs: Any, ) -> None: expected_args_dict = self.get_maybe_enqueue_notifications_parameters( user_id=user_profile.id, acting_user_id=iago.id, message_id=message_id, **kwargs, ) self.assertEqual(args_dict, expected_args_dict) client_descriptor = allocate_event_queue() 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(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_dict = mock_enqueue.call_args_list[0][1] assert_maybe_enqueue_notifications_call_args( args_dict=args_dict, message_id=msg_id, already_notified={"email_notified": False, "push_notified": False}, ) destroy_event_queue(client_descriptor.event_queue.id) # Test the hook with a private message; this should trigger notifications client_descriptor = allocate_event_queue() self.assertTrue(client_descriptor.event_queue.empty()) msg_id = self.send_personal_message(iago, user_profile) 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_dict = mock_enqueue.call_args_list[0][1] assert_maybe_enqueue_notifications_call_args( args_dict=args_dict, message_id=msg_id, pm_email_notify=True, pm_push_notify=True, already_notified={"email_notified": True, "push_notified": True}, ) destroy_event_queue(client_descriptor.event_queue.id) # If `enable_offline_email_notifications` is disabled, email otifications shouldn't # be sent even for PMs user_profile.enable_offline_email_notifications = False user_profile.save() client_descriptor = allocate_event_queue() self.assertTrue(client_descriptor.event_queue.empty()) msg_id = self.send_personal_message(iago, user_profile) 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_dict = mock_enqueue.call_args_list[0][1] assert_maybe_enqueue_notifications_call_args( args_dict=args_dict, message_id=msg_id, pm_email_notify=False, pm_push_notify=True, already_notified={"email_notified": False, "push_notified": True}, ) destroy_event_queue(client_descriptor.event_queue.id) user_profile.enable_offline_email_notifications = True user_profile.save() # Test the hook with a mention; this should trigger notifications client_descriptor = allocate_event_queue() self.assertTrue(client_descriptor.event_queue.empty()) msg_id = self.send_stream_message( self.example_user("iago"), "Denmark", content="@**King Hamlet** what's up?" ) 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_dict = mock_enqueue.call_args_list[0][1] assert_maybe_enqueue_notifications_call_args( args_dict=args_dict, message_id=msg_id, mention_push_notify=True, mention_email_notify=True, already_notified={"email_notified": True, "push_notified": True}, ) destroy_event_queue(client_descriptor.event_queue.id) # If `enable_offline_push_notifications` is disabled, push otifications shouldn't # be sent even for mentions user_profile.enable_offline_push_notifications = False user_profile.save() client_descriptor = allocate_event_queue() self.assertTrue(client_descriptor.event_queue.empty()) msg_id = self.send_personal_message(iago, user_profile) 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_dict = mock_enqueue.call_args_list[0][1] assert_maybe_enqueue_notifications_call_args( args_dict=args_dict, message_id=msg_id, pm_email_notify=True, pm_push_notify=False, already_notified={"email_notified": True, "push_notified": False}, ) destroy_event_queue(client_descriptor.event_queue.id) user_profile.enable_offline_push_notifications = True user_profile.save() # Test the hook with a wildcard mention; this should trigger notifications client_descriptor = allocate_event_queue() self.assertTrue(client_descriptor.event_queue.empty()) msg_id = self.send_stream_message(iago, "Denmark", content="@**all** what's up?") 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_dict = mock_enqueue.call_args_list[0][1] assert_maybe_enqueue_notifications_call_args( args_dict=args_dict, message_id=msg_id, wildcard_mention_email_notify=True, wildcard_mention_push_notify=True, already_notified={"email_notified": True, "push_notified": True}, ) destroy_event_queue(client_descriptor.event_queue.id) # Wildcard mentions in muted streams don't notify. change_subscription_properties(user_profile, stream, sub, {"is_muted": True}) client_descriptor = allocate_event_queue() self.assertTrue(client_descriptor.event_queue.empty()) msg_id = self.send_stream_message(iago, "Denmark", content="@**all** what's up?") 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_dict = mock_enqueue.call_args_list[0][1] assert_maybe_enqueue_notifications_call_args( args_dict=args_dict, wildcard_mention_email_notify=False, wildcard_mention_push_notify=False, message_id=msg_id, already_notified={"email_notified": False, "push_notified": False}, ) destroy_event_queue(client_descriptor.event_queue.id) change_subscription_properties(user_profile, stream, sub, {"is_muted": False}) # With wildcard_mentions_notify=False, we treat the user as not mentioned. user_profile.wildcard_mentions_notify = False user_profile.save() client_descriptor = allocate_event_queue() self.assertTrue(client_descriptor.event_queue.empty()) msg_id = self.send_stream_message(iago, "Denmark", content="@**all** what's up?") 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_dict = mock_enqueue.call_args_list[0][1] assert_maybe_enqueue_notifications_call_args( args_dict=args_dict, message_id=msg_id, wildcard_mention_email_notify=False, wildcard_mention_push_notify=False, already_notified={"email_notified": False, "push_notified": False}, ) destroy_event_queue(client_descriptor.event_queue.id) user_profile.wildcard_mentions_notify = True user_profile.save() # If wildcard_mentions_notify=True for a stream and False for a user, we treat the user # as mentioned for that stream. user_profile.wildcard_mentions_notify = False sub.wildcard_mentions_notify = True user_profile.save() sub.save() client_descriptor = allocate_event_queue() self.assertTrue(client_descriptor.event_queue.empty()) msg_id = self.send_stream_message(iago, "Denmark", content="@**all** what's up?") 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_dict = mock_enqueue.call_args_list[0][1] assert_maybe_enqueue_notifications_call_args( args_dict=args_dict, message_id=msg_id, wildcard_mention_email_notify=True, wildcard_mention_push_notify=True, already_notified={"email_notified": True, "push_notified": True}, ) destroy_event_queue(client_descriptor.event_queue.id) user_profile.wildcard_mentions_notify = True sub.wildcard_mentions_notify = None user_profile.save() sub.save() # If notifications for personal mentions themselves have been turned off, # even turning on `wildcard_mentions_notify` should not send notifications user_profile.enable_offline_email_notifications = False user_profile.wildcard_mentions_notify = True user_profile.save() client_descriptor = allocate_event_queue() self.assertTrue(client_descriptor.event_queue.empty()) msg_id = self.send_stream_message(iago, "Denmark", content="@**all** what's up?") 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_dict = mock_enqueue.call_args_list[0][1] # We've turned off email notifications for personal mentions, but push notifications # for personal mentions are still on. # Because `wildcard_mentions_notify` is True, a message with `@all` should follow the # personal mention settings assert_maybe_enqueue_notifications_call_args( args_dict=args_dict, message_id=msg_id, wildcard_mention_email_notify=False, wildcard_mention_push_notify=True, already_notified={"email_notified": False, "push_notified": True}, ) destroy_event_queue(client_descriptor.event_queue.id) user_profile.enable_offline_email_notifications = True user_profile.wildcard_mentions_notify = True user_profile.save() # Test with a user group mention hamlet_and_cordelia = create_user_group( "hamlet_and_cordelia", [user_profile, cordelia], cordelia.realm ) client_descriptor = allocate_event_queue() self.assertTrue(client_descriptor.event_queue.empty()) msg_id = self.send_stream_message( iago, "Denmark", content="@*hamlet_and_cordelia* what's up?" ) 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_dict = mock_enqueue.call_args_list[0][1] assert_maybe_enqueue_notifications_call_args( args_dict=args_dict, message_id=msg_id, mention_push_notify=True, mention_email_notify=True, mentioned_user_group_id=hamlet_and_cordelia.id, already_notified={"email_notified": True, "push_notified": True}, ) destroy_event_queue(client_descriptor.event_queue.id) remove_user_from_user_group(user_profile, hamlet_and_cordelia) remove_user_from_user_group(cordelia, hamlet_and_cordelia) # Test the hook with a stream message with stream_push_notify change_subscription_properties(user_profile, stream, sub, {"push_notifications": True}) client_descriptor = allocate_event_queue() self.assertTrue(client_descriptor.event_queue.empty()) msg_id = self.send_stream_message(iago, "Denmark", content="what's up everyone?") 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_dict = mock_enqueue.call_args_list[0][1] assert_maybe_enqueue_notifications_call_args( args_dict=args_dict, message_id=msg_id, stream_push_notify=True, stream_email_notify=False, already_notified={"email_notified": False, "push_notified": True}, ) destroy_event_queue(client_descriptor.event_queue.id) # Test the hook with a stream message with stream_email_notify client_descriptor = allocate_event_queue() change_subscription_properties( user_profile, stream, sub, {"push_notifications": False, "email_notifications": True} ) self.assertTrue(client_descriptor.event_queue.empty()) msg_id = self.send_stream_message(iago, "Denmark", content="what's up everyone?") 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_dict = mock_enqueue.call_args_list[0][1] assert_maybe_enqueue_notifications_call_args( args_dict=args_dict, message_id=msg_id, stream_push_notify=False, stream_email_notify=True, already_notified={"email_notified": True, "push_notified": False}, ) destroy_event_queue(client_descriptor.event_queue.id) # Test the hook with stream message with stream_push_notify on # a muted topic, which we should not push notify for client_descriptor = allocate_event_queue() change_subscription_properties( user_profile, stream, sub, {"push_notifications": True, "email_notifications": False} ) self.assertTrue(client_descriptor.event_queue.empty()) do_mute_topic(user_profile, stream, "mutingtest") msg_id = self.send_stream_message( iago, "Denmark", content="what's up everyone?", topic_name="mutingtest", ) 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_dict = mock_enqueue.call_args_list[0][1] assert_maybe_enqueue_notifications_call_args( args_dict=args_dict, message_id=msg_id, already_notified={"email_notified": False, "push_notified": False}, ) destroy_event_queue(client_descriptor.event_queue.id) # Test the hook with stream message with stream_email_notify on # a muted stream, which we should not push notify for client_descriptor = allocate_event_queue() change_subscription_properties( user_profile, stream, sub, {"push_notifications": False, "email_notifications": True} ) self.assertTrue(client_descriptor.event_queue.empty()) change_subscription_properties(user_profile, stream, sub, {"is_muted": True}) msg_id = self.send_stream_message(iago, "Denmark", content="what's up everyone?") 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_dict = mock_enqueue.call_args_list[0][1] assert_maybe_enqueue_notifications_call_args( args_dict=args_dict, message_id=msg_id, already_notified={"email_notified": False, "push_notified": False}, ) destroy_event_queue(client_descriptor.event_queue.id) # Clean up the state we just changed (not necessary unless we add more test code below) change_subscription_properties( user_profile, stream, sub, {"push_notifications": True, "is_muted": False} ) # Test the hook when the sender has been muted result = self.api_post(user_profile, f"/api/v1/users/me/muted_users/{iago.id}") self.assert_json_success(result) client_descriptor = allocate_event_queue() self.assertTrue(client_descriptor.event_queue.empty()) msg_id = self.send_personal_message(iago, user_profile) 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_dict = mock_enqueue.call_args_list[0][1] assert_maybe_enqueue_notifications_call_args( args_dict=args_dict, message_id=msg_id, sender_is_muted=True, pm_email_notify=True, pm_push_notify=True, already_notified={"email_notified": False, "push_notified": False}, ) destroy_event_queue(client_descriptor.event_queue.id) result = self.api_delete(user_profile, f"/api/v1/users/me/muted_users/{iago.id}") self.assert_json_success(result)
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), "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()
def test_end_to_end_missedmessage_hook(self) -> 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") user_profile.enable_online_push_notifications = False user_profile.save() # Fetch the Denmark stream for testing stream = get_stream("Denmark", user_profile.realm) sub = Subscription.objects.get( user_profile=user_profile, recipient__type=Recipient.STREAM, recipient__type_id=stream.id, ) self.login_user(user_profile) def change_subscription_properties( user_profile: UserProfile, stream: Stream, sub: Subscription, properties: Dict[str, bool], ) -> None: for property_name, value in properties.items(): do_change_subscription_property( user_profile, sub, stream, property_name, value, acting_user=None ) def allocate_event_queue() -> ClientDescriptor: result = self.tornado_call( get_events, user_profile, { "apply_markdown": orjson.dumps(True).decode(), "client_gravatar": orjson.dumps(True).decode(), "event_types": orjson.dumps(["message"]).decode(), "user_client": "website", "dont_block": orjson.dumps(True).decode(), }, ) self.assert_json_success(result) queue_id = orjson.loads(result.content)["queue_id"] return get_client_descriptor(queue_id) def destroy_event_queue(queue_id: str) -> None: result = self.tornado_call(cleanup_event_queue, user_profile, {"queue_id": queue_id}) self.assert_json_success(result) client_descriptor = allocate_event_queue() 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_user("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, False, False, "Denmark", False, True, {"email_notified": False, "push_notified": False}, ), ) destroy_event_queue(client_descriptor.event_queue.id) # Test the hook with a private message; this should trigger notifications client_descriptor = allocate_event_queue() self.assertTrue(client_descriptor.event_queue.empty()) msg_id = self.send_personal_message(self.example_user("iago"), user_profile) 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, False, False, None, False, True, {"email_notified": True, "push_notified": True}, ), ) destroy_event_queue(client_descriptor.event_queue.id) # Test the hook with a mention; this should trigger notifications client_descriptor = allocate_event_queue() self.assertTrue(client_descriptor.event_queue.empty()) msg_id = self.send_stream_message( self.example_user("iago"), "Denmark", content="@**King Hamlet** what's up?" ) 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, False, True, False, False, False, "Denmark", False, True, {"email_notified": True, "push_notified": True}, ), ) destroy_event_queue(client_descriptor.event_queue.id) # Test the hook with a wildcard mention; this should trigger notifications client_descriptor = allocate_event_queue() self.assertTrue(client_descriptor.event_queue.empty()) msg_id = self.send_stream_message( self.example_user("iago"), "Denmark", content="@**all** what's up?" ) 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, False, False, True, False, False, "Denmark", False, True, {"email_notified": True, "push_notified": True}, ), ) destroy_event_queue(client_descriptor.event_queue.id) # Test the hook with a wildcard mention sent by the user # themself using a human client; should not notify. client_descriptor = allocate_event_queue() self.assertTrue(client_descriptor.event_queue.empty()) msg_id = self.send_stream_message( self.example_user("hamlet"), "Denmark", content="@**all** what's up?", sending_client_name="website", ) 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, False, False, False, False, False, "Denmark", False, True, {"email_notified": False, "push_notified": False}, ), ) destroy_event_queue(client_descriptor.event_queue.id) # Wildcard mentions in muted streams don't notify. change_subscription_properties(user_profile, stream, sub, {"is_muted": True}) client_descriptor = allocate_event_queue() self.assertTrue(client_descriptor.event_queue.empty()) msg_id = self.send_stream_message( self.example_user("iago"), "Denmark", content="@**all** what's up?" ) 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, False, False, False, False, False, "Denmark", False, True, {"email_notified": False, "push_notified": False}, ), ) destroy_event_queue(client_descriptor.event_queue.id) change_subscription_properties(user_profile, stream, sub, {"is_muted": False}) # With wildcard_mentions_notify=False, we treat the user as not mentioned. user_profile.wildcard_mentions_notify = False user_profile.save() client_descriptor = allocate_event_queue() self.assertTrue(client_descriptor.event_queue.empty()) msg_id = self.send_stream_message( self.example_user("iago"), "Denmark", content="@**all** what's up?" ) 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, False, False, False, False, False, "Denmark", False, True, {"email_notified": False, "push_notified": False}, ), ) destroy_event_queue(client_descriptor.event_queue.id) user_profile.wildcard_mentions_notify = True user_profile.save() # If wildcard_mentions_notify=True for a stream and False for a user, we treat the user # as mentioned for that stream. user_profile.wildcard_mentions_notify = False sub.wildcard_mentions_notify = True user_profile.save() sub.save() client_descriptor = allocate_event_queue() self.assertTrue(client_descriptor.event_queue.empty()) msg_id = self.send_stream_message( self.example_user("iago"), "Denmark", content="@**all** what's up?" ) 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, False, False, True, False, False, "Denmark", False, True, {"email_notified": True, "push_notified": True}, ), ) destroy_event_queue(client_descriptor.event_queue.id) user_profile.wildcard_mentions_notify = True sub.wildcard_mentions_notify = None user_profile.save() sub.save() # Test the hook with a stream message with stream_push_notify change_subscription_properties(user_profile, stream, sub, {"push_notifications": True}) client_descriptor = allocate_event_queue() self.assertTrue(client_descriptor.event_queue.empty()) msg_id = self.send_stream_message( self.example_user("iago"), "Denmark", content="what's up everyone?" ) 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, False, False, False, True, False, "Denmark", False, True, {"email_notified": False, "push_notified": False}, ), ) destroy_event_queue(client_descriptor.event_queue.id) # Test the hook with a stream message with stream_email_notify client_descriptor = allocate_event_queue() change_subscription_properties( user_profile, stream, sub, {"push_notifications": False, "email_notifications": True} ) self.assertTrue(client_descriptor.event_queue.empty()) msg_id = self.send_stream_message( self.example_user("iago"), "Denmark", content="what's up everyone?" ) 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, False, False, False, False, True, "Denmark", False, True, {"email_notified": False, "push_notified": False}, ), ) destroy_event_queue(client_descriptor.event_queue.id) # Test the hook with stream message with stream_push_notify on # a muted topic, which we should not push notify for client_descriptor = allocate_event_queue() change_subscription_properties( user_profile, stream, sub, {"push_notifications": True, "email_notifications": False} ) self.assertTrue(client_descriptor.event_queue.empty()) do_mute_topic(user_profile, stream, "mutingtest") msg_id = self.send_stream_message( self.example_user("iago"), "Denmark", content="what's up everyone?", topic_name="mutingtest", ) 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, False, False, False, False, False, "Denmark", False, True, {"email_notified": False, "push_notified": False}, ), ) destroy_event_queue(client_descriptor.event_queue.id) # Test the hook with stream message with stream_email_notify on # a muted stream, which we should not push notify for client_descriptor = allocate_event_queue() change_subscription_properties( user_profile, stream, sub, {"push_notifications": False, "email_notifications": True} ) self.assertTrue(client_descriptor.event_queue.empty()) change_subscription_properties(user_profile, stream, sub, {"is_muted": True}) msg_id = self.send_stream_message( self.example_user("iago"), "Denmark", content="what's up everyone?" ) 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, False, False, False, False, False, "Denmark", False, True, {"email_notified": False, "push_notified": False}, ), ) destroy_event_queue(client_descriptor.event_queue.id) # Clean up the state we just changed (not necessary unless we add more test code below) change_subscription_properties( user_profile, stream, sub, {"push_notifications": True, "is_muted": False} )