Skip to content

Commit

Permalink
Merge pull request #8 from capcom6/pr-7
Browse files Browse the repository at this point in the history
Some fixed and tests
  • Loading branch information
capcom6 authored May 15, 2023
2 parents 569a7d6 + 5d3ce42 commit db40f10
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 46 deletions.
86 changes: 47 additions & 39 deletions pyapns_client/notification.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import json
import typing
from math import floor
from typing import Any, Dict
from typing import Any, Dict, List, Union


class _PayloadAlert:
Expand All @@ -11,8 +10,8 @@ class _PayloadAlert:

def __init__(
self,
title: typing.Union[str, None] = None,
body: typing.Union[str, None] = None,
title: Union[str, None] = None,
body: Union[str, None] = None,
):
"""
Initializes a new instance of the `_PayloadAlert` class.
Expand All @@ -27,12 +26,13 @@ def __init__(
self.title = title
self.body = body

def to_dict(self, alert_body: typing.Union[str, None] = None):
def to_dict(self, alert_body: Union[str, None] = None):
"""
Converts the alert payload to a dictionary.
Args:
alert_body (str or None): The body text of the alert. If not provided, the `body` attribute of this instance will be used.
alert_body (str or None): The body text of the alert. If not provided, the
`body` attribute of this instance will be used.
Returns:
dict: A dictionary representation of the alert payload.
Expand All @@ -52,16 +52,16 @@ def to_dict(self, alert_body: typing.Union[str, None] = None):
class IOSPayloadAlert(_PayloadAlert):
def __init__(
self,
title=None,
subtitle=None,
body=None,
title_loc_key=None,
title_loc_args=None,
subtitle_loc_key=None,
subtitle_loc_args=None,
loc_key=None,
loc_args=None,
launch_image=None,
title: Union[str, None] = None,
subtitle: Union[str, None] = None,
body: Union[str, None] = None,
title_loc_key: Union[str, None] = None,
title_loc_args: Union[List, None] = None,
subtitle_loc_key: Union[str, None] = None,
subtitle_loc_args: Union[List, None] = None,
loc_key: Union[str, None] = None,
loc_args: Union[List, None] = None,
launch_image: Union[str, None] = None,
):
super().__init__(title=title, body=body)

Expand Down Expand Up @@ -102,7 +102,7 @@ class SafariPayloadAlert(_PayloadAlert):
This class inherits from the `_PayloadAlert` class and adds an `action` attribute.
"""

def __init__(self, title: str, body: str, action: typing.Union[str, None] = None):
def __init__(self, title: str, body: str, action: Union[str, None] = None):
"""
Initializes a new instance of the `SafariPayloadAlert` class.
Expand All @@ -116,12 +116,13 @@ def __init__(self, title: str, body: str, action: typing.Union[str, None] = None

self.action = action

def to_dict(self, alert_body: typing.Union[str, None] = None):
def to_dict(self, alert_body: Union[str, None] = None):
"""
Converts the alert payload to a dictionary.
Args:
alert_body (str or None): The body text of the alert. If not provided, the `body` attribute of this instance will be used.
alert_body (str or None): The body text of the alert. If not provided, the
`body` attribute of this instance will be used.
Returns:
dict: A dictionary representation of the alert payload.
Expand All @@ -138,14 +139,14 @@ class _Payload:
Represents a push notification payload.
Attributes:
MAX_PAYLOAD_SIZE (int): The maximum size of a push notification payload in bytes. See https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/generating_a_remote_notification#overview
MAX_PAYLOAD_SIZE (int): The maximum size of a push notification payload in
bytes. See
https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/generating_a_remote_notification#overview
"""

MAX_PAYLOAD_SIZE = 4096

def __init__(
self, alert: typing.Union[_PayloadAlert, str, None] = None, custom=None
):
def __init__(self, alert: Union[_PayloadAlert, str, None] = None, custom=None):
"""
Initializes a new instance of the `_Payload` class.
Expand All @@ -154,7 +155,7 @@ def __init__(
custom (dict or None): Custom data associated with the payload.
Raises:
ValueError: If `alert` is not a string or a `_PayloadAlert` object.
TypeError: If `alert` is not a string or a `_PayloadAlert` object.
"""
super().__init__()

Expand All @@ -164,18 +165,24 @@ def __init__(
# Recommended to use dictionary, see https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/generating_a_remote_notification#2943360
self.alert = _PayloadAlert(body=alert)
else:
raise ValueError("alert must be a string or a _PayloadAlert object")
value_type = type(alert)
raise TypeError(
f"alert must be a string or _PayloadAlert object, not a '{value_type}'"
)
self.custom = custom or {}

def to_dict(self, alert_body: typing.Union[str, None] = None):
def to_dict(self, alert_body: Union[str, None] = None):
"""
Converts the payload to a dictionary.
Args:
alert_body (str or None): The body text of the alert. If not provided, the `body` attribute of this instance will be used.
alert_body (str or None): The body text of the alert. If not provided, the
`body` attribute of this instance will be used.
Returns:
dict: A dictionary representation of the payload.
Raises:
TypeError: If `alert` is not a string or a `_PayloadAlert` object.
"""
d = {"aps": {}}
if self.alert is not None:
Expand Down Expand Up @@ -208,12 +215,13 @@ def to_json(self):

return json_data

def _to_json(self, alert_body: typing.Union[str, None] = None):
def _to_json(self, alert_body: Union[str, None] = None):
"""
Converts the payload to a JSON string.
Args:
alert_body (str or None): The body text of the alert. If not provided, the `body` attribute of the `_PayloadAlert` object will be used.
alert_body (str or None): The body text of the alert. If not provided, the
`body` attribute of the `_PayloadAlert` object will be used.
Returns:
bytes: A JSON string representation of the payload.
Expand All @@ -226,7 +234,7 @@ def _to_json(self, alert_body: typing.Union[str, None] = None):
class IOSPayload(_Payload):
def __init__(
self,
alert: typing.Union[_PayloadAlert, str, None] = None,
alert: Union[_PayloadAlert, str, None] = None,
badge=None,
sound=None,
category=None,
Expand Down Expand Up @@ -276,15 +284,15 @@ def to_dict(self, alert_body=None):
class SafariPayload(_Payload):
def __init__(
self,
alert: typing.Union[_PayloadAlert, str, None] = None,
url_args: typing.Union[typing.List[str], None] = None,
alert: Union[_PayloadAlert, str, None] = None,
url_args: Union[List[str], None] = None,
custom=None,
):
super().__init__(alert=alert, custom=custom)

self.url_args = url_args or []

def to_dict(self, alert_body: typing.Union[str, None] = None):
def to_dict(self, alert_body: Union[str, None] = None):
d = super().to_dict(alert_body=alert_body)
d["aps"]["url-args"] = self.url_args
return d
Expand Down Expand Up @@ -370,17 +378,17 @@ def __init__(
def get_headers(self):
headers = {"Content-Type": "application/json; charset=utf-8"}
if self.topic:
headers["apns-topic"] = self.topic
headers["apns-topic"] = str(self.topic)
if self.apns_id:
headers["apns-id"] = self.apns_id
headers["apns-id"] = str(self.apns_id)
if self.collapse_id:
headers["apns-collapse-id"] = self.collapse_id
headers["apns-collapse-id"] = str(self.collapse_id)
if self.priority:
headers["apns-priority"] = self.priority
headers["apns-priority"] = str(self.priority)
if self.expiration:
headers["apns-expiration"] = self.expiration
headers["apns-expiration"] = str(self.expiration)
if self.push_type:
headers["apns-push-type"] = self.push_type
headers["apns-push-type"] = str(self.push_type)
return headers

def get_json_data(self):
Expand Down
84 changes: 77 additions & 7 deletions tests/payload_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@

import pytest

from pyapns_client import IOSPayload, IOSPayloadAlert, SafariPayload, SafariPayloadAlert
from pyapns_client import (
IOSNotification,
IOSPayload,
IOSPayloadAlert,
SafariPayload,
SafariPayloadAlert,
)


# iOS
Expand Down Expand Up @@ -60,11 +66,40 @@ def test_ios_payload():
},
"extra": "something",
}
assert (
ios_payload.to_json()
== b'{"aps":{"alert":{"body":"my_alert"},"badge":2,"category":"my_category","content-available":1,"mutable-content":1,"sound":"chime","thread-id":"42"},"extra":"something"}'
assert ios_payload.to_json() == (
b'{"aps":{"alert":{"body":"my_alert"},"badge":2,"category":"my_category",'
b'"content-available":1,"mutable-content":1,"sound":"chime","thread-id":"42"},'
b'"extra":"something"}'
)


def test_ios_notification():
ios_payload = IOSPayload(
alert="my_alert",
badge=2,
sound="chime",
content_available=True,
mutable_content=True,
category="my_category",
custom={"extra": "something"},
thread_id="42",
)
notification = IOSNotification(
ios_payload, "com.example.test", priority=IOSNotification.PRIORITY_LOW
)

assert notification.get_json_data() == (
b'{"aps":{"alert":{"body":"my_alert"},"badge":2,"category":"my_category",'
b'"content-available":1,"mutable-content":1,"sound":"chime","thread-id":"42"},'
b'"extra":"something"}'
)

assert notification.get_headers() == {
"Content-Type": "application/json; charset=utf-8",
"apns-priority": "5",
"apns-topic": "com.example.test",
}


def test_ios_payload_with_ios_payload_alert(ios_payload_alert: IOSPayloadAlert):
payload = IOSPayload(
Expand Down Expand Up @@ -100,12 +135,47 @@ def test_ios_payload_with_ios_payload_alert(ios_payload_alert: IOSPayloadAlert):
},
"extra": "something",
}
assert (
payload.to_json()
== b'{"aps":{"alert":{"body":"body","launch-image":"img","loc-args":["body_loc_a"],"loc-key":"body_loc_k","subtitle":"subtitle","subtitle-loc-args":["subtitle_loc_a"],"subtitle-loc-key":"subtitle_loc_k","title":"title","title-loc-args":["title_loc_a"],"title-loc-key":"title_loc_k"},"badge":2,"category":"my_category","content-available":1,"mutable-content":1,"sound":"chime","thread-id":"42"},"extra":"something"}'
assert payload.to_json() == (
b'{"aps":{"alert":{"body":"body","launch-image":"img","loc-args":["body_loc_a"],'
b'"loc-key":"body_loc_k","subtitle":"subtitle","subtitle-loc-args":["subtitle_loc_a"],'
b'"subtitle-loc-key":"subtitle_loc_k","title":"title","title-loc-args":["title_loc_a"],'
b'"title-loc-key":"title_loc_k"},'
b'"badge":2,"category":"my_category","content-available":1,"mutable-content":1,'
b'"sound":"chime","thread-id":"42"},"extra":"something"}'
)


def test_ios_notification_with_ios_payload_alert(ios_payload_alert: IOSPayloadAlert):
ios_payload = IOSPayload(
alert=ios_payload_alert,
badge=2,
sound="chime",
content_available=True,
mutable_content=True,
category="my_category",
custom={"extra": "something"},
thread_id="42",
)
notification = IOSNotification(
ios_payload, "com.example.test", priority=IOSNotification.PRIORITY_LOW
)

assert notification.get_json_data() == (
b'{"aps":{"alert":{"body":"body","launch-image":"img","loc-args":["body_loc_a"],'
b'"loc-key":"body_loc_k","subtitle":"subtitle","subtitle-loc-args":["subtitle_loc_a"],'
b'"subtitle-loc-key":"subtitle_loc_k","title":"title","title-loc-args":["title_loc_a"],'
b'"title-loc-key":"title_loc_k"},'
b'"badge":2,"category":"my_category","content-available":1,"mutable-content":1,'
b'"sound":"chime","thread-id":"42"},"extra":"something"}'
)

assert notification.get_headers() == {
"Content-Type": "application/json; charset=utf-8",
"apns-priority": "5",
"apns-topic": "com.example.test",
}


# Safari
@pytest.fixture
def safari_payload_alert(action: typing.Union[str, None]):
Expand Down

0 comments on commit db40f10

Please sign in to comment.