mirror of
https://github.com/caronc/apprise.git
synced 2024-11-21 23:53:23 +01:00
OneSignal to support custom data in payload (#1163)
Co-authored-by: phantom943 <105282577+phantom943@users.noreply.github.com>
This commit is contained in:
parent
631ce107cd
commit
d22ce8d5b7
@ -82,7 +82,7 @@ class NotifyOneSignal(NotifyBase):
|
|||||||
setup_url = 'https://github.com/caronc/apprise/wiki/Notify_onesignal'
|
setup_url = 'https://github.com/caronc/apprise/wiki/Notify_onesignal'
|
||||||
|
|
||||||
# Notification
|
# Notification
|
||||||
notify_url = "https://onesignal.com/api/v1/notifications"
|
notify_url = "https://api.onesignal.com/notifications"
|
||||||
|
|
||||||
# Allows the user to specify the NotifyImageSize object
|
# Allows the user to specify the NotifyImageSize object
|
||||||
image_size = NotifyImageSize.XY_72
|
image_size = NotifyImageSize.XY_72
|
||||||
@ -161,6 +161,12 @@ class NotifyOneSignal(NotifyBase):
|
|||||||
'type': 'bool',
|
'type': 'bool',
|
||||||
'default': False,
|
'default': False,
|
||||||
},
|
},
|
||||||
|
'contents': {
|
||||||
|
'name': _('Enable Contents'),
|
||||||
|
'type': 'bool',
|
||||||
|
'default': True,
|
||||||
|
'map_to': 'use_contents',
|
||||||
|
},
|
||||||
'template': {
|
'template': {
|
||||||
'alias_of': 'template',
|
'alias_of': 'template',
|
||||||
},
|
},
|
||||||
@ -175,9 +181,21 @@ class NotifyOneSignal(NotifyBase):
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
# Define our token control
|
||||||
|
template_kwargs = {
|
||||||
|
'custom': {
|
||||||
|
'name': _('Custom Data'),
|
||||||
|
'prefix': ':',
|
||||||
|
},
|
||||||
|
'postback': {
|
||||||
|
'name': _('Postback Data'),
|
||||||
|
'prefix': '+',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
def __init__(self, app, apikey, targets=None, include_image=True,
|
def __init__(self, app, apikey, targets=None, include_image=True,
|
||||||
template=None, subtitle=None, language=None, batch=False,
|
template=None, subtitle=None, language=None, batch=None,
|
||||||
**kwargs):
|
use_contents=None, custom=None, postback=None, **kwargs):
|
||||||
"""
|
"""
|
||||||
Initialize OneSignal
|
Initialize OneSignal
|
||||||
|
|
||||||
@ -201,7 +219,14 @@ class NotifyOneSignal(NotifyBase):
|
|||||||
raise TypeError(msg)
|
raise TypeError(msg)
|
||||||
|
|
||||||
# Prepare Batch Mode Flag
|
# Prepare Batch Mode Flag
|
||||||
self.batch_size = self.default_batch_size if batch else 1
|
self.batch_size = self.default_batch_size if (
|
||||||
|
batch if batch is not None else
|
||||||
|
self.template_args['batch']['default']) else 1
|
||||||
|
|
||||||
|
# Prepare Use Contents Flag
|
||||||
|
self.use_contents = True if (
|
||||||
|
use_contents if use_contents is not None else
|
||||||
|
self.template_args['contents']['default']) else False
|
||||||
|
|
||||||
# Place a thumbnail image inline with the message body
|
# Place a thumbnail image inline with the message body
|
||||||
self.include_image = include_image
|
self.include_image = include_image
|
||||||
@ -273,6 +298,27 @@ class NotifyOneSignal(NotifyBase):
|
|||||||
'Detected OneSignal Player ID: %s' %
|
'Detected OneSignal Player ID: %s' %
|
||||||
self.targets[OneSignalCategory.PLAYER][-1])
|
self.targets[OneSignalCategory.PLAYER][-1])
|
||||||
|
|
||||||
|
# Custom Data
|
||||||
|
self.custom_data = {}
|
||||||
|
if custom and isinstance(custom, dict):
|
||||||
|
self.custom_data.update(custom)
|
||||||
|
|
||||||
|
elif custom:
|
||||||
|
msg = 'The specified OneSignal Custom Data ' \
|
||||||
|
'({}) are not identified as a dictionary.'.format(custom)
|
||||||
|
self.logger.warning(msg)
|
||||||
|
raise TypeError(msg)
|
||||||
|
|
||||||
|
# Postback Data
|
||||||
|
self.postback_data = {}
|
||||||
|
if postback and isinstance(postback, dict):
|
||||||
|
self.postback_data.update(postback)
|
||||||
|
|
||||||
|
elif postback:
|
||||||
|
msg = 'The specified OneSignal Postback Data ' \
|
||||||
|
'({}) are not identified as a dictionary.'.format(postback)
|
||||||
|
self.logger.warning(msg)
|
||||||
|
raise TypeError(msg)
|
||||||
return
|
return
|
||||||
|
|
||||||
def send(self, body, title='', notify_type=NotifyType.INFO, **kwargs):
|
def send(self, body, title='', notify_type=NotifyType.INFO, **kwargs):
|
||||||
@ -291,14 +337,9 @@ class NotifyOneSignal(NotifyBase):
|
|||||||
|
|
||||||
payload = {
|
payload = {
|
||||||
'app_id': self.app,
|
'app_id': self.app,
|
||||||
|
|
||||||
'headings': {
|
|
||||||
self.language: title if title else self.app_desc,
|
|
||||||
},
|
|
||||||
'contents': {
|
'contents': {
|
||||||
self.language: body,
|
self.language: body,
|
||||||
},
|
},
|
||||||
|
|
||||||
# Sending true wakes your app from background to run custom native
|
# Sending true wakes your app from background to run custom native
|
||||||
# code (Apple interprets this as content-available=1).
|
# code (Apple interprets this as content-available=1).
|
||||||
# Note: Not applicable if the app is in the "force-quit" state
|
# Note: Not applicable if the app is in the "force-quit" state
|
||||||
@ -307,6 +348,33 @@ class NotifyOneSignal(NotifyBase):
|
|||||||
'content_available': True,
|
'content_available': True,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.template_id:
|
||||||
|
# Store template information
|
||||||
|
payload['template_id'] = self.template_id
|
||||||
|
|
||||||
|
if not self.use_contents:
|
||||||
|
# Only if a template is defined can contents be removed
|
||||||
|
del payload['contents']
|
||||||
|
|
||||||
|
# Set our data if defined
|
||||||
|
if self.custom_data:
|
||||||
|
payload.update({
|
||||||
|
'custom_data': self.custom_data,
|
||||||
|
})
|
||||||
|
|
||||||
|
# Set our postback data if defined
|
||||||
|
if self.postback_data:
|
||||||
|
payload.update({
|
||||||
|
'data': self.postback_data,
|
||||||
|
})
|
||||||
|
|
||||||
|
if title:
|
||||||
|
# Display our title if defined
|
||||||
|
payload.update({
|
||||||
|
'headings': {
|
||||||
|
self.language: title,
|
||||||
|
}})
|
||||||
|
|
||||||
if self.subtitle:
|
if self.subtitle:
|
||||||
payload.update({
|
payload.update({
|
||||||
'subtitle': {
|
'subtitle': {
|
||||||
@ -314,9 +382,6 @@ class NotifyOneSignal(NotifyBase):
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
if self.template_id:
|
|
||||||
payload['template_id'] = self.template_id
|
|
||||||
|
|
||||||
# Acquire our large_icon image URL (if set)
|
# Acquire our large_icon image URL (if set)
|
||||||
image_url = None if not self.include_image \
|
image_url = None if not self.include_image \
|
||||||
else self.image_url(notify_type)
|
else self.image_url(notify_type)
|
||||||
@ -406,6 +471,17 @@ class NotifyOneSignal(NotifyBase):
|
|||||||
# Extend our parameters
|
# Extend our parameters
|
||||||
params.update(self.url_parameters(privacy=privacy, *args, **kwargs))
|
params.update(self.url_parameters(privacy=privacy, *args, **kwargs))
|
||||||
|
|
||||||
|
# Save our template data
|
||||||
|
params.update(
|
||||||
|
{':{}'.format(k): v for k, v in self.custom_data.items()})
|
||||||
|
|
||||||
|
# Save our postback data
|
||||||
|
params.update(
|
||||||
|
{'+{}'.format(k): v for k, v in self.postback_data.items()})
|
||||||
|
|
||||||
|
if self.use_contents != self.template_args['contents']['default']:
|
||||||
|
params['contents'] = 'yes' if self.use_contents else 'no'
|
||||||
|
|
||||||
return '{schema}://{tp_id}{app}@{apikey}/{targets}?{params}'.format(
|
return '{schema}://{tp_id}{app}@{apikey}/{targets}?{params}'.format(
|
||||||
schema=self.secure_protocol,
|
schema=self.secure_protocol,
|
||||||
tp_id='{}:'.format(
|
tp_id='{}:'.format(
|
||||||
@ -485,6 +561,13 @@ class NotifyOneSignal(NotifyBase):
|
|||||||
'batch',
|
'batch',
|
||||||
NotifyOneSignal.template_args['batch']['default']))
|
NotifyOneSignal.template_args['batch']['default']))
|
||||||
|
|
||||||
|
# Get Use Contents Boolean (if set)
|
||||||
|
results['use_contents'] = \
|
||||||
|
parse_bool(
|
||||||
|
results['qsd'].get(
|
||||||
|
'contents',
|
||||||
|
NotifyOneSignal.template_args['contents']['default']))
|
||||||
|
|
||||||
# The API Key is stored in the hostname
|
# The API Key is stored in the hostname
|
||||||
results['apikey'] = NotifyOneSignal.unquote(results['host'])
|
results['apikey'] = NotifyOneSignal.unquote(results['host'])
|
||||||
|
|
||||||
@ -516,4 +599,10 @@ class NotifyOneSignal(NotifyBase):
|
|||||||
results['language'] = \
|
results['language'] = \
|
||||||
NotifyOneSignal.unquote(results['qsd']['lang'])
|
NotifyOneSignal.unquote(results['qsd']['lang'])
|
||||||
|
|
||||||
|
# Store our custom data
|
||||||
|
results['custom'] = results['qsd:']
|
||||||
|
|
||||||
|
# Store our postback data
|
||||||
|
results['postback'] = results['qsd+']
|
||||||
|
|
||||||
return results
|
return results
|
||||||
|
@ -26,6 +26,10 @@
|
|||||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
# POSSIBILITY OF SUCH DAMAGE.
|
# POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
from json import loads
|
||||||
|
from unittest import mock
|
||||||
|
import pytest
|
||||||
|
import requests
|
||||||
from apprise.plugins.one_signal import NotifyOneSignal
|
from apprise.plugins.one_signal import NotifyOneSignal
|
||||||
from helpers import AppriseURLTester
|
from helpers import AppriseURLTester
|
||||||
from apprise import Apprise
|
from apprise import Apprise
|
||||||
@ -105,6 +109,16 @@ apprise_url_tests = (
|
|||||||
# Test Kwargs
|
# Test Kwargs
|
||||||
'instance': NotifyOneSignal,
|
'instance': NotifyOneSignal,
|
||||||
}),
|
}),
|
||||||
|
('onesignal://?apikey=abc&template=tp&app=123&to=playerid&body=no'
|
||||||
|
'&:key1=val1&:key2=val2', {
|
||||||
|
# Test Kwargs
|
||||||
|
'instance': NotifyOneSignal,
|
||||||
|
}),
|
||||||
|
('onesignal://?apikey=abc&template=tp&app=123&to=playerid&body=no'
|
||||||
|
'&+key1=val1&+key2=val2', {
|
||||||
|
# Test Kwargs
|
||||||
|
'instance': NotifyOneSignal,
|
||||||
|
}),
|
||||||
('onesignal://appid@apikey/#segment/playerid/', {
|
('onesignal://appid@apikey/#segment/playerid/', {
|
||||||
'instance': NotifyOneSignal,
|
'instance': NotifyOneSignal,
|
||||||
# throw a bizzare code forcing us to fail to look it up
|
# throw a bizzare code forcing us to fail to look it up
|
||||||
@ -244,3 +258,106 @@ def test_plugin_onesignal_edge_cases():
|
|||||||
|
|
||||||
# Individual queries
|
# Individual queries
|
||||||
assert len(obj) == 16
|
assert len(obj) == 16
|
||||||
|
|
||||||
|
# custom must be a dictionary
|
||||||
|
with pytest.raises(TypeError):
|
||||||
|
NotifyOneSignal(
|
||||||
|
app='appid', apikey='key', targets=['@user'], custom='not-a-dict')
|
||||||
|
|
||||||
|
# postback must be a dictionary
|
||||||
|
with pytest.raises(TypeError):
|
||||||
|
NotifyOneSignal(
|
||||||
|
app='appid', apikey='key', targets=['@user'],
|
||||||
|
custom=[], postback='not-a-dict')
|
||||||
|
|
||||||
|
|
||||||
|
@mock.patch('requests.post')
|
||||||
|
def test_plugin_onesignal_notifications(mock_post):
|
||||||
|
"""
|
||||||
|
OneSignal() Notifications Support
|
||||||
|
|
||||||
|
"""
|
||||||
|
# Prepare Mock
|
||||||
|
mock_post.return_value = requests.Request()
|
||||||
|
mock_post.return_value.status_code = requests.codes.ok
|
||||||
|
|
||||||
|
# Load URL with Template
|
||||||
|
instance = Apprise.instantiate(
|
||||||
|
'onesignal://templateid:appid@apikey/@user/?:key1=value1&+key3=value3')
|
||||||
|
|
||||||
|
# Validate that it loaded okay
|
||||||
|
assert isinstance(instance, NotifyOneSignal)
|
||||||
|
|
||||||
|
response = instance.notify("hello world")
|
||||||
|
assert response is True
|
||||||
|
assert mock_post.call_count == 1
|
||||||
|
assert mock_post.call_args_list[0][0][0] == \
|
||||||
|
'https://api.onesignal.com/notifications'
|
||||||
|
|
||||||
|
details = mock_post.call_args_list[0]
|
||||||
|
payload = loads(details[1]['data'])
|
||||||
|
|
||||||
|
assert payload == {
|
||||||
|
'app_id': 'appid',
|
||||||
|
'contents': {'en': 'hello world'},
|
||||||
|
'content_available': True,
|
||||||
|
'template_id': 'templateid',
|
||||||
|
'custom_data': {'key1': 'value1'},
|
||||||
|
'data': {'key3': 'value3'},
|
||||||
|
'large_icon': 'https://github.com/caronc/apprise'
|
||||||
|
'/raw/master/apprise/assets/themes/default/apprise-info-72x72.png',
|
||||||
|
'small_icon': 'https://github.com/caronc/apprise'
|
||||||
|
'/raw/master/apprise/assets/themes/default/apprise-info-32x32.png',
|
||||||
|
'include_external_user_ids': ['@user']}
|
||||||
|
|
||||||
|
mock_post.reset_mock()
|
||||||
|
|
||||||
|
# Load URL with Template and disable body
|
||||||
|
instance = Apprise.instantiate(
|
||||||
|
'onesignal://templateid:appid@apikey/@user/?contents=no')
|
||||||
|
|
||||||
|
# Validate that it loaded okay
|
||||||
|
assert isinstance(instance, NotifyOneSignal)
|
||||||
|
|
||||||
|
response = instance.notify("hello world")
|
||||||
|
assert response is True
|
||||||
|
assert mock_post.call_count == 1
|
||||||
|
assert mock_post.call_args_list[0][0][0] == \
|
||||||
|
'https://api.onesignal.com/notifications'
|
||||||
|
|
||||||
|
details = mock_post.call_args_list[0]
|
||||||
|
payload = loads(details[1]['data'])
|
||||||
|
|
||||||
|
assert payload == {
|
||||||
|
'app_id': 'appid',
|
||||||
|
'content_available': True,
|
||||||
|
'template_id': 'templateid',
|
||||||
|
'large_icon': 'https://github.com/caronc/apprise'
|
||||||
|
'/raw/master/apprise/assets/themes/default/apprise-info-72x72.png',
|
||||||
|
'small_icon': 'https://github.com/caronc/apprise'
|
||||||
|
'/raw/master/apprise/assets/themes/default/apprise-info-32x32.png',
|
||||||
|
'include_external_user_ids': ['@user']}
|
||||||
|
|
||||||
|
# Now set a title
|
||||||
|
mock_post.reset_mock()
|
||||||
|
|
||||||
|
response = instance.notify("hello world", title="mytitle")
|
||||||
|
|
||||||
|
assert response is True
|
||||||
|
assert mock_post.call_count == 1
|
||||||
|
assert mock_post.call_args_list[0][0][0] == \
|
||||||
|
'https://api.onesignal.com/notifications'
|
||||||
|
|
||||||
|
details = mock_post.call_args_list[0]
|
||||||
|
payload = loads(details[1]['data'])
|
||||||
|
|
||||||
|
assert payload == {
|
||||||
|
'app_id': 'appid',
|
||||||
|
'headings': {'en': 'mytitle'},
|
||||||
|
'content_available': True,
|
||||||
|
'template_id': 'templateid',
|
||||||
|
'large_icon': 'https://github.com/caronc/apprise'
|
||||||
|
'/raw/master/apprise/assets/themes/default/apprise-info-72x72.png',
|
||||||
|
'small_icon': 'https://github.com/caronc/apprise'
|
||||||
|
'/raw/master/apprise/assets/themes/default/apprise-info-32x32.png',
|
||||||
|
'include_external_user_ids': ['@user']}
|
||||||
|
Loading…
Reference in New Issue
Block a user