From b4fcab56586805fec16ab4fbaea1cc1b06591b32 Mon Sep 17 00:00:00 2001 From: moden Date: Tue, 29 May 2018 13:01:13 +0300 Subject: [PATCH 1/3] Extend PayloadAlert with all keys supported --- apns.py | 67 ++++++++++++++++++++++++++++++++++++++------------------ tests.py | 16 +++++++++++--- 2 files changed, 59 insertions(+), 24 deletions(-) diff --git a/apns.py b/apns.py index 33655b1..1226def 100644 --- a/apns.py +++ b/apns.py @@ -268,10 +268,21 @@ def write(self, string): class PayloadAlert(object): - def __init__(self, body=None, title = None, subtitle = None, action_loc_key=None, loc_key=None, - loc_args=None, launch_image=None): - super(PayloadAlert, self).__init__() - + """ + Payload for APNS alert. + https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/PayloadKeyReference.html + """ + def __init__(self, + body=None, + title=None, + subtitle=None, + action_loc_key=None, + loc_key=None, + loc_args=None, + launch_image=None, + title_loc_key=None, + title_loc_args=None): + self.body = body self.title = title self.subtitle = subtitle @@ -279,25 +290,39 @@ def __init__(self, body=None, title = None, subtitle = None, action_loc_key=None self.loc_key = loc_key self.loc_args = loc_args self.launch_image = launch_image + self.title_loc_key = title_loc_key + self.title_loc_args = title_loc_args + + self._dict = { + 'body': self.body, + 'title': self.title, + 'subtitle': self.subtitle, + 'action-loc-key': self.action_loc_key, + 'loc-key': self.loc_key, + 'loc-args': self.loc_args, + 'launch-image': self.launch_image, + 'title-loc-key': self.title_loc_key, + 'title-loc-args': self.title_loc_args + } def dict(self): - d = {} - - if self.body: - d['body'] = self.body - if self.title: - d['title'] = self.title - if self.subtitle: - d['subtitle'] = self.subtitle - if self.action_loc_key: - d['action-loc-key'] = self.action_loc_key - if self.loc_key: - d['loc-key'] = self.loc_key - if self.loc_args: - d['loc-args'] = self.loc_args - if self.launch_image: - d['launch-image'] = self.launch_image - return d + cleared = { + key: value + for (key, value) + in self._dict.items() + if value is not None + } + return cleared + + def __eq__(self, other): + return self.dict() == other.dict() + + def __ne__(self, other): + return self.dict() != other.dict() + + def __repr__(self): + return 'PayloadAlert(**{})'.format(self.dict()) + class PayloadTooLargeError(Exception): def __init__(self, payload_size): diff --git a/tests.py b/tests.py index fb17a54..97ca644 100644 --- a/tests.py +++ b/tests.py @@ -188,9 +188,19 @@ def testFrame(self): frame = Frame() frame.add_item(token_hex, payload, identifier, expiry, priority) - f1 = bytearray(b'\x02\x00\x00\x00t\x01\x00 \xb5\xbb\x9d\x80\x14\xa0\xf9\xb1\xd6\x1e!\xe7\x96\xd7\x8d\xcc\xdf\x13R\xf2<\xd3(\x12\xf4\x85\x0b\x87\x8a\xe4\x94L\x02\x00<{"aps":{"sound":"default","badge":4,"alert":"Hello World!"}}\x03\x00\x04\x00\x00\x00\x01\x04\x00\x04\x00\x00\x0e\x10\x05\x00\x01\n') - f2 = bytearray(b'\x02\x00\x00\x00t\x01\x00 \xb5\xbb\x9d\x80\x14\xa0\xf9\xb1\xd6\x1e!\xe7\x96\xd7\x8d\xcc\xdf\x13R\xf2<\xd3(\x12\xf4\x85\x0b\x87\x8a\xe4\x94L\x02\x00<{"aps":{"sound":"default","alert":"Hello World!","badge":4}}\x03\x00\x04\x00\x00\x00\x01\x04\x00\x04\x00\x00\x0e\x10\x05\x00\x01\n') - self.assertTrue(f1 == frame.get_frame() or f2 == frame.get_frame()) + frame_bytes = frame.get_frame() + + prefix = frame_bytes[:43] + data = frame_bytes[43: -18] + postfix = frame_bytes[-18:] + + self.assertEqual(prefix, b'\x02\x00\x00\x00t\x01\x00 \xb5\xbb\x9d\x80\x14\xa0\xf9\xb1\xd6\x1e!\xe7\x96\xd7\x8d\xcc\xdf\x13R\xf2<\xd3(\x12\xf4\x85\x0b\x87\x8a\xe4\x94L\x02\x00<') + self.assertEqual( + json.loads(data.decode()), + json.loads('{"aps":{"sound":"default","badge":4,' + '"alert":"Hello World!"}}') + ) + self.assertEqual(postfix, b'\x03\x00\x04\x00\x00\x00\x01\x04\x00\x04\x00\x00\x0e\x10\x05\x00\x01\n') def testPayloadTooLargeError(self): # The maximum size of the JSON payload is MAX_PAYLOAD_LENGTH From 07e7659a5c862a5248592349160d0c50fe7da427 Mon Sep 17 00:00:00 2001 From: Denis Matiychuk Date: Tue, 29 May 2018 18:55:15 +0300 Subject: [PATCH 2/3] Update setup.py --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 1d66940..3ff86d5 100644 --- a/setup.py +++ b/setup.py @@ -10,5 +10,5 @@ py_modules = ['apns'], scripts = ['apns-send'], url = 'http://29.io/', - version = '2.0.1', + version = 'canwehatch.2.0.1', ) From d0a8c17f5e0211ed20f660cd4bfca5084bc18729 Mon Sep 17 00:00:00 2001 From: moden Date: Wed, 12 Sep 2018 11:37:04 +0300 Subject: [PATCH 3/3] JSON serializable PayloadAlert --- apns.py | 58 +++++++++++++++++++------------------------------------- setup.py | 2 +- tests.py | 7 +++++++ 3 files changed, 28 insertions(+), 39 deletions(-) mode change 100644 => 100755 apns.py mode change 100644 => 100755 tests.py diff --git a/apns.py b/apns.py old mode 100644 new mode 100755 index 1226def..532053b --- a/apns.py +++ b/apns.py @@ -267,7 +267,7 @@ def write(self, string): return self._connection().write(string) -class PayloadAlert(object): +class PayloadAlert(dict): """ Payload for APNS alert. https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/PayloadKeyReference.html @@ -282,46 +282,28 @@ def __init__(self, launch_image=None, title_loc_key=None, title_loc_args=None): - - self.body = body - self.title = title - self.subtitle = subtitle - self.action_loc_key = action_loc_key - self.loc_key = loc_key - self.loc_args = loc_args - self.launch_image = launch_image - self.title_loc_key = title_loc_key - self.title_loc_args = title_loc_args - - self._dict = { - 'body': self.body, - 'title': self.title, - 'subtitle': self.subtitle, - 'action-loc-key': self.action_loc_key, - 'loc-key': self.loc_key, - 'loc-args': self.loc_args, - 'launch-image': self.launch_image, - 'title-loc-key': self.title_loc_key, - 'title-loc-args': self.title_loc_args - } - - def dict(self): - cleared = { - key: value - for (key, value) - in self._dict.items() - if value is not None + dict_ = { + 'body': body, + 'title': title, + 'subtitle': subtitle, + 'action-loc-key': action_loc_key, + 'loc-key': loc_key, + 'loc-args': loc_args, + 'launch-image': launch_image, + 'title-loc-key': title_loc_key, + 'title-loc-args': title_loc_args } - return cleared - def __eq__(self, other): - return self.dict() == other.dict() + # init dictionary with non None items + super(PayloadAlert, self).__init__( + { + key: value for (key, value) + in dict_.items() if value is not None + } + ) - def __ne__(self, other): - return self.dict() != other.dict() - - def __repr__(self): - return 'PayloadAlert(**{})'.format(self.dict()) + def dict(self): + return self class PayloadTooLargeError(Exception): diff --git a/setup.py b/setup.py index 3ff86d5..644ff24 100644 --- a/setup.py +++ b/setup.py @@ -10,5 +10,5 @@ py_modules = ['apns'], scripts = ['apns-send'], url = 'http://29.io/', - version = 'canwehatch.2.0.1', + version = 'canwehatch.2.0.2', ) diff --git a/tests.py b/tests.py old mode 100644 new mode 100755 index 97ca644..6a6254c --- a/tests.py +++ b/tests.py @@ -5,6 +5,7 @@ from random import random import hashlib +import json import os import time import unittest @@ -130,6 +131,11 @@ def testPayloadAlert(self): self.assertTrue('body' not in d) self.assertEqual(d['loc-key'], 'wibble') + def testPayloadAlertJSONSerializable(self): + pa = PayloadAlert('foo', action_loc_key='bar', loc_key='wibble', + loc_args=['king', 'kong'], launch_image='wobble') + self.assertEqual(pa, json.loads(json.dumps(pa))) + def testPayload(self): # Payload with just alert p = Payload(alert=PayloadAlert('foo')) @@ -219,5 +225,6 @@ def testPayloadTooLargeError(self): self.assertRaises(PayloadTooLargeError, Payload, u'\u0100' * (int(max_raw_payload_bytes / 2) + 1)) + if __name__ == '__main__': unittest.main()