notifications: Add function for cancelling GCM notifications.

This adds a new function called handle_remove_push_notification in
zerver/lib/push_notifications.py which requires user_profile id and
the message id which has to be removed in the function.

For now, the function only supports GCM (and is mostly there for
prototyping).

The payload which is being delivered needs to contain the narrow
information and the content of the message.
This commit is contained in:
Kunal Gupta
2018-07-28 18:01:45 +05:30
committed by Tim Abbott
parent 5f8d193bb7
commit bc43eefbfb
2 changed files with 86 additions and 0 deletions

View File

@@ -548,6 +548,39 @@ def get_gcm_payload(user_profile: UserProfile, message: Message) -> Dict[str, An
}) })
return data return data
def handle_remove_push_notification(user_profile_id: int, remove_message: Dict[str, Any]) -> None:
"""This should be called when a message that had previously had a
mobile push executed is read. This triggers a mobile push notifica
mobile app when the message is read on the server, to remove the
message from the notification.
"""
user_profile = get_user_profile_by_id(user_profile_id)
message = access_message(user_profile, remove_message['message_id'])[0]
gcm_payload = get_common_payload(message)
gcm_payload.update({
'event': 'remove',
'zulip_message_id': remove_message['message_id'], # message_id is reserved for CCS
})
if uses_notification_bouncer():
try:
send_notifications_to_bouncer(user_profile_id,
{},
gcm_payload)
except requests.ConnectionError: # nocoverage
def failure_processor(event: Dict[str, Any]) -> None:
logging.warning(
"Maximum retries exceeded for trigger:%s event:push_notification" % (
event['user_profile_id']))
return
android_devices = list(PushDeviceToken.objects.filter(user=user_profile,
kind=PushDeviceToken.GCM))
if android_devices:
send_android_push_notification(android_devices, gcm_payload)
@statsd_increment("push_notifications") @statsd_increment("push_notifications")
def handle_push_notification(user_profile_id: int, missed_message: Dict[str, Any]) -> None: def handle_push_notification(user_profile_id: int, missed_message: Dict[str, Any]) -> None:
""" """

View File

@@ -536,6 +536,59 @@ class HandlePushNotificationTest(PushNotificationTest):
mock_send_android.assert_called_with(android_devices, mock_send_android.assert_called_with(android_devices,
{'gcm': True}) {'gcm': True})
def test_send_remove_notifications_to_bouncer(self) -> None:
user_profile = self.example_user('hamlet')
message = self.get_message(Recipient.PERSONAL, type_id=1)
UserMessage.objects.create(
user_profile=user_profile,
message=message
)
remove_message = {
'message_id': message.id,
}
with self.settings(PUSH_NOTIFICATION_BOUNCER_URL=True), \
mock.patch('zerver.lib.push_notifications'
'.send_notifications_to_bouncer') as mock_send_android, \
mock.patch('zerver.lib.push_notifications.get_common_payload',
return_value={'gcm': True}):
apn.handle_remove_push_notification(user_profile.id, remove_message)
mock_send_android.assert_called_with(user_profile.id, {},
{'gcm': True,
'event': 'remove',
'zulip_message_id': message.id})
def test_non_bouncer_push_remove(self) -> None:
message = self.get_message(Recipient.PERSONAL, type_id=1)
UserMessage.objects.create(
user_profile=self.user_profile,
message=message
)
for token in [u'dddd']:
PushDeviceToken.objects.create(
kind=PushDeviceToken.GCM,
token=apn.hex_to_b64(token),
user=self.user_profile)
android_devices = list(
PushDeviceToken.objects.filter(user=self.user_profile,
kind=PushDeviceToken.GCM))
remove_message = {
'message_id': message.id,
}
with mock.patch('zerver.lib.push_notifications'
'.send_android_push_notification') as mock_send_android, \
mock.patch('zerver.lib.push_notifications.get_common_payload',
return_value={'gcm': True}):
apn.handle_remove_push_notification(self.user_profile.id, remove_message)
mock_send_android.assert_called_with(android_devices,
{'gcm': True,
'event': 'remove',
'zulip_message_id': message.id})
def test_user_message_does_not_exist(self) -> None: def test_user_message_does_not_exist(self) -> None:
"""This simulates a condition that should only be an error if the user is """This simulates a condition that should only be an error if the user is
not long-term idle; we fake it, though, in the sense that the user should not long-term idle; we fake it, though, in the sense that the user should