diff --git a/zerver/lib/push_notifications.py b/zerver/lib/push_notifications.py index dc030c45e6..33b6983391 100644 --- a/zerver/lib/push_notifications.py +++ b/zerver/lib/push_notifications.py @@ -10,7 +10,7 @@ import re import time import random -from typing import Any, Dict, List, Optional, SupportsInt, Tuple, Type, Union +from typing import Any, Dict, List, Optional, SupportsInt, Tuple, Type, Union, cast from django.conf import settings from django.db import IntegrityError, transaction @@ -429,7 +429,7 @@ def push_notifications_enabled() -> bool: return True return False -def get_alert_from_message(message: Message) -> str: +def get_gcm_alert(message: Message) -> str: """ Determine what alert string to display based on the missed messages. """ @@ -519,6 +519,29 @@ def get_common_payload(message: Message) -> Dict[str, Any]: return data +def get_apns_alert_title(message: Message) -> str: + """ + On an iOS notification, this is the first bolded line. + """ + if message.recipient.type == Recipient.HUDDLE: + recipients = cast(List[Dict[str, Any]], get_display_recipient(message.recipient)) + return ', '.join(sorted(r['full_name'] for r in recipients)) + elif message.is_stream_message(): + return "#%s > %s" % (message.stream_name, message.topic_name(),) + # For personal PMs, we just show the sender name. + return message.sender.full_name + +def get_apns_alert_subtitle(message: Message) -> str: + """ + On an iOS notification, this is the second bolded line. + """ + if message.trigger == "mentioned": + return message.sender.full_name + " mentioned you:" + elif message.recipient.type == Recipient.PERSONAL: + return "" + # For group PMs, or regular messages to a stream, just use a colon to indicate this is the sender. + return message.sender.full_name + ":" + def get_apns_payload(user_profile: UserProfile, message: Message) -> Dict[str, Any]: zulip_data = get_common_payload(message) zulip_data.update({ @@ -528,7 +551,8 @@ def get_apns_payload(user_profile: UserProfile, message: Message) -> Dict[str, A content, _ = truncate_content(get_mobile_push_content(message.rendered_content)) apns_data = { 'alert': { - 'title': get_alert_from_message(message), + 'title': get_apns_alert_title(message), + 'subtitle': get_apns_alert_subtitle(message), 'body': content, }, 'badge': 0, # TODO: set badge count in a better way @@ -542,7 +566,7 @@ def get_gcm_payload(user_profile: UserProfile, message: Message) -> Dict[str, An data.update({ 'user': user_profile.email, 'event': 'message', - 'alert': get_alert_from_message(message), + 'alert': get_gcm_alert(message), 'zulip_message_id': message.id, # message_id is reserved for CCS 'time': datetime_to_timestamp(message.pub_date), 'content': content, diff --git a/zerver/tests/test_push_notifications.py b/zerver/tests/test_push_notifications.py index 070ba95449..7c32492ace 100644 --- a/zerver/tests/test_push_notifications.py +++ b/zerver/tests/test_push_notifications.py @@ -731,9 +731,40 @@ class TestAPNs(PushNotificationTest): self.assertEqual( apn.modernize_apns_payload(payload), payload) - + class TestGetAPNsPayload(PushNotificationTest): - def test_get_apns_payload(self) -> None: + def test_get_apns_payload_personal_message(self) -> None: + user_profile = self.example_user("othello") + message_id = self.send_personal_message( + self.example_email('hamlet'), + self.example_email('othello'), + 'Content of personal message', + ) + message = Message.objects.get(id=message_id) + message.trigger = 'private_message' + payload = apn.get_apns_payload(user_profile, message) + expected = { + 'alert': { + 'title': 'King Hamlet', + 'subtitle': '', + 'body': message.content, + }, + 'badge': 0, + 'custom': { + 'zulip': { + 'message_ids': [message.id], + 'recipient_type': 'private', + 'sender_email': 'hamlet@zulip.com', + 'sender_id': 4, + 'server': settings.EXTERNAL_HOST, + 'realm_id': message.sender.realm.id, + 'realm_uri': message.sender.realm.uri, + } + } + } + self.assertDictEqual(payload, expected) + + def test_get_apns_payload_huddle_message(self) -> None: user_profile = self.example_user("othello") message_id = self.send_huddle_message( self.sender.email, @@ -743,7 +774,8 @@ class TestGetAPNsPayload(PushNotificationTest): payload = apn.get_apns_payload(user_profile, message) expected = { 'alert': { - 'title': "New private group message from King Hamlet", + 'title': 'Cordelia Lear, King Hamlet, Othello, the Moor of Venice', + 'subtitle': 'King Hamlet:', 'body': message.content, }, 'badge': 0, @@ -765,7 +797,38 @@ class TestGetAPNsPayload(PushNotificationTest): } self.assertDictEqual(payload, expected) - def test_get_apns_payload_stream(self): + def test_get_apns_payload_stream_message(self): + # type: () -> None + user_profile = self.example_user("hamlet") + stream = Stream.objects.filter(name='Verona').get() + message = self.get_message(Recipient.STREAM, stream.id) + message.trigger = 'push_stream_notify' + message.stream_name = 'Verona' + payload = apn.get_apns_payload(user_profile, message) + expected = { + 'alert': { + 'title': '#Verona > Test Message', + 'subtitle': 'King Hamlet:', + 'body': message.content, + }, + 'badge': 0, + 'custom': { + 'zulip': { + 'message_ids': [message.id], + 'recipient_type': 'stream', + 'sender_email': 'hamlet@zulip.com', + 'sender_id': 4, + "stream": apn.get_display_recipient(message.recipient), + "topic": message.subject, + 'server': settings.EXTERNAL_HOST, + 'realm_id': message.sender.realm.id, + 'realm_uri': message.sender.realm.uri, + } + } + } + self.assertDictEqual(payload, expected) + + def test_get_apns_payload_stream_mention(self): # type: () -> None user_profile = self.example_user("othello") stream = Stream.objects.filter(name='Verona').get() @@ -775,7 +838,8 @@ class TestGetAPNsPayload(PushNotificationTest): payload = apn.get_apns_payload(user_profile, message) expected = { 'alert': { - 'title': "New mention from King Hamlet", + 'title': '#Verona > Test Message', + 'subtitle': 'King Hamlet mentioned you:', 'body': message.content, }, 'badge': 0, @@ -806,7 +870,8 @@ class TestGetAPNsPayload(PushNotificationTest): payload = apn.get_apns_payload(user_profile, message) expected = { 'alert': { - 'title': "New private group message from King Hamlet", + 'title': 'Cordelia Lear, King Hamlet, Othello, the Moor of Venice', + 'subtitle': "King Hamlet:", 'body': "***REDACTED***", }, 'badge': 0,