# -*-coding:utf-8-*-
#
# Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import numbers
import re
import six
[docs]
class Message(object):
"""A message that can be sent Huawei Cloud Messaging.
:param data: A string value.
:param notification: An instance of ``messaging.Notification`` (optional).
:param android: An instance of ``messaging.Android`` (optional).
:param apns: APSN related message definition
:param web_push: Web Push related message definition
:param token: token list, must be tuple (optional).
:param topic: message topic, must be string (optional).
:param condition: message condition, must be string (optional).
"""
def __init__(
self,
data=None,
notification=None,
android=None,
apns=None,
web_push=None,
token=None,
topic=None,
condition=None,
):
MessageValidator.check_message(
data,
notification,
android,
apns,
web_push,
token,
topic,
condition,
)
self.data = data
self.notification = notification
self.android = android
self.apns = apns
self.web_push = web_push
self.token = token
self.topic = topic
self.condition = condition
[docs]
class Notification(object):
"""A notification that can be included in a message.
:param title: Title of the notification (optional).
:param body: Body of the notification (optional).
:param image: Image url of the notification (optional).
"""
def __init__(self, title=None, body=None, image=None):
MessageValidator.check_notification(title, body, image)
self.title = title
self.body = body
self.image = image
# ----------------------------------------------------------------------------------------------------------------------
[docs]
class APNsConfig(object):
"""Please refer to the Apple APNS API reference.
https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CommunicatingwithAPNs.html
"""
def __init__(self, headers=None, payload=None, apns_hms_options=None):
MessageValidator.check_apns_config(
headers=headers,
payload=payload,
apns_hms_options=apns_hms_options,
)
self.headers = headers
self.payload = payload
self.apns_hms_options = apns_hms_options
[docs]
class APNsPayload(object):
"""APNs payload definition.
"""
def __init__(self, aps, **kwargs):
MessageValidator.check_apns_payload(aps=aps)
self.aps = aps
self.custom_data = kwargs
[docs]
class APNsAps(object):
"""APNs aps definition.
https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/PayloadKeyReference.html#//apple_ref/doc/uid/TP40008194-CH17-SW1
one sample is as follows:
.. code-block:: json
{
"aps" : {
"alert" : {
"title" : "Game Request",
"body" : "Bob wants to play poker",
"action-loc-key" : "PLAY"
"loc-key" : "GAME_PLAY_REQUEST_FORMAT",
"loc-args" : [ "Jenna", "Frank"],
"content-available" : 1
},
"badge" : 5,
"sound" : "bingbong.aiff",
},
"acme1" : "bar",
"acme2" : [ "bang", "whiz" ]
}
"""
def __init__(
self,
alert=None,
badge=None,
sound=None,
content_available=None,
category=None,
thread_id=None,
mutable_content=None,
custom_data=None,
):
MessageValidator.check_apns_payload_aps(
alert=alert,
badge=badge,
sound=sound,
content_available=content_available,
category=category,
thread_id=thread_id,
mutable_content=mutable_content,
custom_data=custom_data,
)
self.alert = alert
self.badge = badge
self.sound = sound
self.content_available = content_available
self.category = category
self.thread_id = thread_id
self.mutable_content = mutable_content
self.custom_data = custom_data
[docs]
class APNsAlert(object):
"""An alert that can be included in ``messaging.Aps``.
:param title: Title of the notification (optional).
:param body: Body of the notification (optional).
:param loc_key: Localized key to body (optional).
:param loc_args: Localized args to body (optional).
:param title_loc_key: Localized key to title (optional).
:param title_loc_args: Localized args to title (optional).
:param action_loc_key: Localized key to action (optional).
:param launch_image: Image url of the notification (optional).
:param custom_data: Custom data (optional).
"""
def __init__(
self,
title=None,
body=None,
loc_key=None,
loc_args=None,
title_loc_key=None,
title_loc_args=None,
action_loc_key=None,
launch_image=None,
custom_data=None,
):
MessageValidator.check_apns_payload_aps_alert(
title=title,
body=body,
loc_key=loc_key,
loc_args=loc_args,
title_loc_key=title_loc_key,
title_loc_args=title_loc_args,
action_loc_key=action_loc_key,
launch_image=launch_image,
custom_data=custom_data,
)
self.title = title
self.body = body
self.loc_key = loc_key
self.loc_args = loc_args
self.title_loc_key = title_loc_key
self.title_loc_args = title_loc_args
self.action_loc_key = action_loc_key
self.launch_image = launch_image
self.custom_data = custom_data
[docs]
class APNsHMSOptions(object):
"""Options for features provided by the FCM SDK for iOS.
:param target_user_type: Developer or Commercial enviroment
"""
def __init__(self, target_user_type=None):
MessageValidator.check_apns_hms_options(
target_user_type=target_user_type)
self.target_user_type = target_user_type
# ----------------------------------------------------------------------------------------------------------------------
[docs]
class WebPushConfig(object):
"""Web push-specific options that can be included in a message.
For Web Push Specification Reference: https://tools.ietf.org/html/rfc8030#section-5
For mozilla implementation: https://developer.mozilla.org/en-US/docs/Web/API/notification
:param headers: A dictionary of headers (optional). Refer Web push Specification for supported headers.
:param notification: A ``messaging.WebPushNotification`` to be included in the message (optional).
:param hms_options: A ``WebPushHMSOptions`` instance to be included in the message(optional).
"""
TTL_HEADER = "ttl"
URGENCY_HEADER = "urgency"
TOPIC_HEADER = "topic"
def __init__(
self,
headers=None,
data=None,
notification=None,
hms_options=None,
):
MessageValidator.check_webpush_config(
headers,
data,
notification,
hms_options,
)
""" Refer to https://tools.ietf.org/html/rfc7240 """
self.headers = headers
""" message deliver to the end application directly """
self.data = data
""" Refer to WebPushNotification """
self.notification = notification
""" Refer to WebPushHMSOptions"""
self.hms_options = hms_options
[docs]
class WebPushNotification(object):
"""Web Push Notification.
"""
def __init__(
self,
title=None,
body=None,
icon=None,
actions=None,
badge=None,
data=None,
dir=None,
image=None,
lang=None,
renotify=None,
require_interaction=None,
silent=None,
tag=None,
timestamp=None,
vibrate=None,
):
MessageValidator.check_webpush_notification(
title=title,
body=body,
icon=icon,
actions=actions,
badge=badge,
data=data,
dir=dir,
image=image,
lang=lang,
renotify=renotify,
require_interaction=require_interaction,
silent=silent,
tag=tag,
timestamp=timestamp,
vibrate=vibrate,
)
self.title = title
self.body = body
""" Refer to WebPushNotificationAction """
self.actions = actions
self.badge = badge
self.data = data
self.dir = dir
self.icon = icon
self.image = image
self.lang = lang
self.renotify = renotify
self.require_interaction = require_interaction
self.silent = silent
self.tag = tag
self.timestamp = timestamp
self.vibrate = vibrate
[docs]
class WebPushNotificationAction(object):
"""The action for web push notification.
:param action:
:param title:
:param icon:
"""
def __init__(self, action=None, title=None, icon=None):
MessageValidator.check_webpush_notification_action(
action=action, title=title, icon=icon
)
self.action = action
self.icon = icon
self.title = title
[docs]
class WebPushHMSOptions(object):
"""Optional link option.
:param link: The link to be included in the message.
"""
def __init__(self, link=None):
MessageValidator.check_webpush_hms_options(link)
self.link = link
# ----------------------------------------------------------------------------------------------------------------------
[docs]
class AndroidConfig(object):
"""Android-specific options that can be included in a message.
:param collapse_key: An identifier for a group of messages (optional).
:param urgency: A string indicating how important the message is.
The value must be one of "NORMAL" or "HIGH".
:param ttl: The time-to-live duration of the message in seconds (optional).
:param bi_tag: A developer-defined message identifier (optional).
:param fast_app_target: A boolean indicating if the message should be sent as a fast app launch (optional).
:param notification: A ``messaging.AndroidNotification`` to be included in the message (optional).
:param data: A ``messaging.AndroidData`` to be included in the message (optional).
:param category: A string indicating the category of the message (optional).
"""
HIGH_PRIORITY = "HIGH"
NORMAL_PRIORITY = "NORMAL"
def __init__(
self,
collapse_key=None,
urgency="NORMAL",
ttl=None,
bi_tag=None,
fast_app_target=None,
notification=None,
data=None,
category=None,
):
MessageValidator.check_android_config(
collapse_key,
urgency,
ttl,
bi_tag,
fast_app_target,
notification,
data,
)
self.collapse_key = collapse_key
self.urgency = urgency
self.ttl = ttl
self.bi_tag = bi_tag
self.fast_app_target = fast_app_target
self.notification = notification
self.data = data
self.category = category
[docs]
class AndroidNotification(object):
"""Android-specific notification parameters.
:param title: The notification's title (optional).
:param body: The notification's body text (optional).
:param icon: The name of a drawable resource that provides the notification icon (optional).
:param color: The color of the notification icon in ARGB format (optional).
:param sound: The sound to play when the device receives the notification (optional).
:param default_sound: A boolean indicating if the notification should use the default sound (optional).
:param tag: The notification tag (optional).
:param click_action: The action associated with a user click on the notification (optional).
:param body_loc_key: The key to the body string in the app's string resources (optional).
:param body_loc_args: An array of resource keys that will be used in place of the format specifiers in body_loc_key (optional).
:param title_loc_key: The key to the title string in the app's string resources (optional).
:param title_loc_args: An array of resource keys that will be used in place of the format specifiers in title_loc_key (optional).
:param multi_lang_key: The key to the title string in the app's string resources (optional).
:param channel_id: The notification's channel ID (optional).
:param notify_summary: The summary of the notification (optional).
:param image: The URL of the image to display in the notification (optional).
:param style: The style of the notification (optional).
:param big_title: The big title of the notification (optional).
:param big_body: The big body of the notification (optional).
:param auto_clear: The auto clear duration of the notification (optional).
:param notify_id: The notification ID (optional).
:param group: The notification group (optional).
:param badge: The notification badge (optional).
:param ticker: The notification ticker (optional).
:param auto_cancel: The auto cancel duration of the notification (optional).
:param when: The notification's timestamp (optional).
:param importance: The notification's importance (optional).
:param use_default_vibrate: A boolean indicating if the notification should use the default vibrate (optional).
:param use_default_light: A boolean indicating if the notification should use the default light (optional).
:param vibrate_config: The vibrate configuration (optional).
:param visibility: The visibility of the notification (optional).
:param light_settings: The light settings (optional).
:param foreground_show: A boolean indicating if the notification should be shown in the foreground (optional).
"""
PRIORITY_LOW = "LOW"
PRIORITY_DEFAULT = "NORMAL"
PRIORITY_HIGH = "HIGH"
VISIBILITY_UNSPECIFIED = "VISIBILITY_UNSPECIFIED"
PRIVATE = "PRIVATE"
PUBLIC = "PUBLIC"
SECRET = "SECRET"
def __init__(
self,
title=None,
body=None,
icon=None,
color=None,
sound=None,
default_sound=None,
tag=None,
click_action=None,
body_loc_key=None,
body_loc_args=None,
title_loc_key=None,
title_loc_args=None,
multi_lang_key=None,
channel_id=None,
notify_summary=None,
image=None,
style=None,
big_title=None,
big_body=None,
auto_clear=None,
notify_id=None,
group=None,
badge=None,
ticker=None,
auto_cancel=None,
when=None,
importance=None,
use_default_vibrate=True,
use_default_light=True,
vibrate_config=None,
visibility=None,
light_settings=None,
foreground_show=False,
):
MessageValidator.check_android(
title=title,
body=body,
icon=icon,
color=color,
sound=sound,
default_sound=default_sound,
tag=tag,
click_action=click_action,
body_loc_key=body_loc_key,
body_loc_args=body_loc_args,
title_loc_key=title_loc_key,
title_loc_args=title_loc_args,
multi_lang_key=multi_lang_key,
channel_id=channel_id,
notify_summary=notify_summary,
image=image,
style=style,
big_title=big_title,
big_body=big_body,
auto_clear=auto_clear,
notify_id=notify_id,
group=group,
badge=badge,
ticker=ticker,
auto_cancel=auto_cancel,
when=when,
importance=importance,
use_default_vibrate=use_default_vibrate,
use_default_light=use_default_light,
vibrate_config=vibrate_config,
visibility=visibility,
light_settings=light_settings,
foreground_show=foreground_show,
)
self.title = title
self.body = body
self.icon = icon
self.color = color
self.sound = sound
self.default_sound = default_sound
self.tag = tag
self.click_action = click_action
self.body_loc_key = body_loc_key
self.body_loc_args = body_loc_args
self.title_loc_key = title_loc_key
self.title_loc_args = title_loc_args
self.multi_lang_key = multi_lang_key
self.channel_id = channel_id
self.notify_summary = notify_summary
self.image = image
self.style = style
self.big_title = big_title
self.big_body = big_body
self.auto_clear = auto_clear
self.notify_id = notify_id
self.group = group
self.badge = badge
self.ticker = ticker
self.auto_cancel = auto_cancel
self.when = when
self.importance = importance
self.use_default_vibrate = use_default_vibrate
self.use_default_light = use_default_light
self.vibrate_config = vibrate_config
self.visibility = visibility
self.light_settings = light_settings
self.foreground_show = foreground_show
[docs]
class AndroidClickAction(object):
"""A ClickAction that can be included in a message.android.notification.
:param action_type: type of the android.notification (optional).
:param intent: intent of the android.notification (optional).
:param url: url of the android.notification (optional).
:param action: action definition for push message
1: to specific activity of application
2: specific URL
3: to specific application
"""
def __init__(self, action_type=None, intent=None, action=None, url=None):
MessageValidator.check_click_action(
action_type=action_type, intent=intent, action=action, url=url
)
self.action_type = action_type
self.intent = intent
self.action = action
self.url = url
[docs]
class AndroidBadgeNotification(object):
"""A BadgeNotification that can be included in a message.android.notification.
:param add_num: message number of badge notification in the android.notification (optional).
:param set_num: set the specific number of badge notification (optional).
:param clazz: message class of badge notification in the android.notification (optional).
"""
def __init__(self, add_num=None, set_num=None, clazz=None):
MessageValidator.check_badge_notification(
add_num=add_num, set_num=set_num, clazz=clazz
)
self.add_num = add_num
self.set_num = set_num
self.clazz = clazz
[docs]
class AndroidLightSettings(object):
"""A LightSettings that can be included in a message.android.notification.
:param color: light color of the android.notification (optional).
:param light_on_duration: light on duration of the android.notification (optional).
:param light_off_duration: light off duration of the android.notification (optional).
.. code-block:: json
"light_settings": {
"color":{
"alpha":0,
"red":0,
"green":1,
"blue":1
},
"light_on_duration":"3.5",
"light_off_duration":"5S"
}
"""
def __init__(
self,
color=None,
light_on_duration=None,
light_off_duration=None,
):
MessageValidator.check_light_settings(
color=color,
light_on_duration=light_on_duration,
light_off_duration=light_off_duration,
)
self.color = color
self.light_on_duration = light_on_duration
self.light_off_duration = light_off_duration
[docs]
class AndroidLightSettingsColor(object):
"""A LightSettingsColor that can be included in a message.android.notification.
:param alpha: light color alpha of the android.notification (optional).
:param red: light color red of the android.notification (optional).
:param green: light color green of the android.notification (optional).
:param blue: light color blue of the android.notification (optional).
.. code-block:: json
"color": {
"alpha":0,
"red":0,
"green":1,
"blue":1
}
"""
def __init__(self, alpha=None, red=None, green=None, blue=None):
MessageValidator.check_light_settings_color(
alpha=alpha, red=red, green=green, blue=blue
)
self.alpha = alpha
self.red = red
self.green = green
self.blue = blue
# --------------------------------------------------------------------------------------------------------------------
class MessageValidator(object):
"""Message validation utilities.
Methods provided in this class raise ValueErrors if any validations fail.
"""
@classmethod
def check_https_url(cls, hint, value):
cls.check_string(hint, value)
if value is not None and not re.match(r"^https:/{2}\w.+$", value):
raise ValueError("{0} must be a valid https url.".format(hint))
@classmethod
def check_string(cls, hint, value, non_empty=False):
"""Checks if the given value is a string."""
if value is None:
return None
if not isinstance(value, six.string_types):
if non_empty:
raise ValueError(
"{0} must be a non-empty string.".format(hint))
else:
raise ValueError("{0} must be a string.".format(hint))
if non_empty and not value:
raise ValueError("{0} must be a non-empty string.".format(hint))
return value
@classmethod
def assert_string_values(cls, hint, value, *args):
"""Check the class value should be an instance of string.
and related values should be within *args
:param hint: prompt message
:param value: the real value
:param args: the specific value list
:return:
"""
if value is None:
return None
if not isinstance(value, six.string_types):
raise ValueError("{0} must be a string.".format(hint))
for v in args:
if value.__eq__(v):
return value
raise ValueError("{} must be a value within{}.".format(hint, args))
@classmethod
def check_string_list(cls, label, value):
"""Checks if the given value is a list comprised only of strings."""
if value is None or value == []:
return None
if not isinstance(value, list):
raise ValueError("{0} must be a list of strings.".format(label))
non_str = [k for k in value if not isinstance(k, six.string_types)]
if non_str:
raise ValueError(
"{0} must not contain non-string values.".format(label))
return value
@classmethod
def check_boolean(cls, hint, value):
"""Checks if the given value is a string."""
if value is None:
return None
if not isinstance(value, bool):
raise ValueError("{0} must be a boolean.".format(hint))
return value
@classmethod
def count_boolean(cls, *args):
count = 0
for v in args:
if v:
count += 1
return count
@classmethod
def check_not_all_none(cls, hint, *args):
total_size = len(args)
count = 0
for data in args:
if data is None:
count += 1
if total_size == count:
raise ValueError(hint)
@classmethod
def check_type(cls, class_obj, class_type, hint):
if (class_obj is not None) and (not isinstance(class_obj, class_type)):
raise ValueError(hint)
@classmethod
def check_type_list(cls, label, value, cls_type):
"""Checks if the given value is a list comprised only of numbers."""
if value is None or value == []:
return None
if not isinstance(value, list):
raise ValueError(
"{0} must be a list of {1}.".format(label, cls_type))
non_number = [k for k in value if not isinstance(k, cls_type)]
if non_number:
raise ValueError(
"{0} must not contain non-{1} values.".format(label, cls_type)
)
return value
@classmethod
def check_number(cls, label, value):
if value is None:
return None
if not isinstance(value, numbers.Number):
raise ValueError("{0} must be a number.".format(label))
return value
@classmethod
def check_number_span(cls, label, value, min, max):
if value is None:
return None
if not isinstance(value, numbers.Number):
raise ValueError("{0} must be a number.".format(label))
if value < min or value > max:
raise ValueError(
"{0} must be within {1} to {2}.".format(label, min, max))
return value
@classmethod
def assert_integer_values(cls, hint, value, *args):
"""Check the class value should be an instance of integer.
and related values should be within *args
:param hint: prompt message
:param value: the real value
:param args: the specific value list
:return:
"""
if value is None:
return None
if not isinstance(value, six.integer_types):
raise ValueError("{0} must be a integer.".format(hint))
for v in args:
if value == v:
return value
raise ValueError("{} must be a value within{}.".format(hint, args))
@classmethod
def check_number_list(cls, label, value):
if value is None or value == []:
return None
if not isinstance(value, list):
raise ValueError("{0} must be a list of numbers.".format(label))
non_number = [k for k in value if not isinstance(k, numbers.Number)]
if non_number:
raise ValueError(
"{0} must not contain non-number values.".format(label))
return value
@classmethod
def check_string_dict(cls, label, value):
if value is None or value == {}:
return None
if not isinstance(value, dict):
raise ValueError("{0} must be a dictionary.".format(label))
non_str = [k for k in value if not isinstance(k, six.string_types)]
if non_str:
raise ValueError(
"{0} must not contain non-string keys.".format(label))
return value
# ------------------------------------------------------------------------------------------------------------------
@classmethod
def check_message(
cls,
data,
notification,
android,
apns,
web_push,
token,
topic,
condition,
):
"""Check whether the message parameter is valid or not.
:param data:
:param notification:
:param android:
:param apns:
:param web_push:
:param token:
:param topic:
:param condition:
:return:
"""
# data must be string
cls.check_string(hint="Message.data", value=data)
# notification
if (notification is not None) and (
not isinstance(
notification,
Notification,
)
):
raise ValueError(
"notification must be an instance of Notification class")
# android / APNs / Web Push
# if notification message(data is None), one of android / APNs
# / Web Push must be present
if data is None:
cls.check_not_all_none(
"Message.data is None, one of Message.android/Message.apns/Message.webpush \
must be present",
android,
apns,
web_push,
)
cls.check_type(
android,
AndroidConfig,
"android must be an instance of AndroidConfig class",
)
cls.check_type(
apns,
APNsConfig,
"apns must be an instance of APNsConfig class",
)
cls.check_type(
web_push,
WebPushConfig,
"web_push must be an instance of WebPushConfig class",
)
"""token, topic, condition"""
# [token, topic, condition] only one not None
target_count = cls.count_boolean(
token is not None, topic is not None, condition is not None
)
if target_count != 1:
raise ValueError(
"Exactly one of token, topic or condition must be specified."
)
# token must be tuple or list
if token is not None:
if not isinstance(token, tuple) and not isinstance(token, list):
raise ValueError("token must be a tuple or a list")
if len(token) > 1000:
raise ValueError(
"token must not contain more than 1000 tokens")
cls.check_string(hint="Message.topic", value=topic)
cls.check_string(hint="Message.condition", value=condition)
@classmethod
def check_notification(cls, title, body, image):
cls.check_string(hint="Notification.title", value=title)
cls.check_string(hint="Notification.body", value=body)
cls.check_https_url(hint="Notification.image", value=image)
@classmethod
def check_android_config(
cls,
collapse_key,
urgency,
ttl,
bi_tag,
fast_app_target,
notification,
data,
):
# collapse_key
cls.check_number("AndroidConfig.collapse_key", collapse_key)
# urgency
cls.assert_string_values(
"AndroidConfig.urgency",
urgency,
AndroidConfig.HIGH_PRIORITY,
AndroidConfig.NORMAL_PRIORITY,
)
# ttl
cls.check_string(hint="AndroidConfig.ttl", value=ttl)
# bi_tag
cls.check_string(hint="AndroidConfig.bi_tag", value=bi_tag)
# fast_app_target
cls.check_number_span(
"AndroidConfig.fast_app_target", fast_app_target, 1, 2)
# notification
cls.check_type(
notification,
AndroidNotification,
hint="notification must be an instance of AndroidNotification",
)
# data
cls.check_string(hint="AndroidConfig.data", value=data)
@classmethod
def check_android(
cls,
title,
body,
icon,
color,
sound,
default_sound,
tag,
click_action,
body_loc_key,
body_loc_args,
title_loc_key,
title_loc_args,
multi_lang_key,
channel_id,
notify_summary,
image,
style,
big_title,
big_body,
auto_clear,
notify_id,
group,
badge,
ticker,
auto_cancel,
when,
importance,
use_default_vibrate,
use_default_light,
vibrate_config,
visibility,
light_settings,
foreground_show,
):
# title
cls.check_string(hint="AndroidNotification.title", value=title)
# body
cls.check_string(hint="AndroidNotification.body", value=body)
# icon
cls.check_string(hint="AndroidNotification.icon", value=icon)
# color
cls.check_string(hint="AndroidNotification.color", value=color)
# sound
cls.check_string(hint="AndroidNotification.sound", value=sound)
# default_sound
cls.check_boolean(
hint="AndroidNotification.default_sound", value=default_sound)
# tag
cls.check_string(hint="AndroidNotification.tag", value=tag)
# click_action
cls.check_type(
click_action,
AndroidClickAction,
hint="click_action must be an instance of AndroidClickAction",
)
# body_loc_key
cls.check_string(
hint="AndroidNotification.body_loc_key", value=body_loc_key)
# body_loc_args
if (
(body_loc_args is not None)
and (not isinstance(body_loc_args, tuple))
and (not isinstance(body_loc_args, list))
):
raise ValueError(
"AndroidNotification.body_loc_args must be an instance of tuple or list"
)
# title_loc_key
cls.check_string(
hint="AndroidNotification.title_loc_key", value=title_loc_key)
# title_loc_args
if (title_loc_args is not None) and (
not isinstance(title_loc_args, tuple)
and not isinstance(title_loc_args, list)
):
raise ValueError(
"AndroidNotification.title_loc_args must be an instance of tuple or list"
)
# multi_lang_key
if multi_lang_key is not None:
if not isinstance(multi_lang_key, dict):
raise ValueError(
"AndroidNotification.multi_lang_key must be a dict.")
# channel_id
cls.check_string(
hint="AndroidNotification.channel_id", value=channel_id)
# notify_summary
cls.check_string(
hint="AndroidNotification.notify_summary", value=notify_summary
)
#
# image
cls.check_https_url(hint="AndroidNotification.image", value=image)
# style
if style is not None:
if style not in [0, 1, 2]:
raise ValueError("AndroidNotification.style must in [0, 1, 2]")
# big_title, big_body
if style == 1:
if (big_title is None) or (not isinstance(big_title, str)):
raise ValueError(
"AndroidNotification.big_title must be valid string when style is 1"
)
if (big_body is None) and (not isinstance(big_body, str)):
raise ValueError(
"AndroidNotification.big_body must be valid string when style is 1"
)
# auto_clear
cls.check_number(
label="AndroidNotification.auto_clear ", value=auto_clear)
# notify_id
cls.check_number(
label="AndroidNotification.notify_id ", value=notify_id)
# group
cls.check_string(hint="AndroidNotification.group", value=group)
# badge
cls.check_type(
badge,
AndroidBadgeNotification,
"badge should be an instance of AndroidBadgeNotification",
)
# ticker
cls.check_string(hint="AndroidNotification.ticker", value=ticker)
# auto_cancel
cls.check_boolean(
hint="AndroidNotification.auto_cancel", value=auto_cancel)
# when
cls.check_string(hint="AndroidNotification.when", value=when)
# importance
cls.assert_string_values(
"AndroidNotification.importance",
importance,
AndroidNotification.PRIORITY_DEFAULT,
AndroidNotification.PRIORITY_HIGH,
AndroidNotification.PRIORITY_LOW,
)
# use_default_vibrate
cls.check_boolean(
hint="AndroidNotification.use_default_vibrate",
value=use_default_vibrate,
)
# use_default_light
cls.check_boolean(
hint="AndroidNotification.use_default_light",
value=use_default_light,
)
# vibrate_config
cls.check_string_list(
label="AndroidNotification.vibrate_config",
value=vibrate_config,
)
# visibility
cls.assert_string_values(
"AndroidNotification.visibility",
visibility,
AndroidNotification.PRIVATE,
AndroidNotification.PUBLIC,
AndroidNotification.SECRET,
AndroidNotification.VISIBILITY_UNSPECIFIED,
)
# light_settings
cls.check_type(
light_settings,
AndroidLightSettings,
"light_settings should be an instance of AndroidLightSettings",
)
# foreground_show
cls.check_boolean(
hint="AndroidNotification.foreground_show",
value=foreground_show,
)
@classmethod
def check_badge_notification(cls, add_num, set_num, clazz):
# add_num must be int
cls.check_number_span(
label="AndroidBadgeNotification.add_num",
value=add_num,
min=0,
max=100,
)
# set_num must be int
cls.check_number_span(
label="AndroidBadgeNotification.set_num",
value=set_num,
min=0,
max=100,
)
# clazz
cls.check_string(
hint="AndroidBadgeNotification.clazz",
value=clazz,
)
@classmethod
def check_click_action(cls, action_type, intent, action, url):
# type must be in [1, 4]
if (action_type is None) or (action_type not in [1, 2, 3, 4]):
raise ValueError("ClickAction.type must be in [1, 2, 3, 4]")
# intent, if type is 1, intent or action must be present or both
if action_type == 1:
count = cls.count_boolean(isinstance(
intent, str), isinstance(action, str))
if count <= 0:
raise ValueError(
"ClickAction.intent or ClickAction.action must be present or both when click_type is 1"
)
# url, if type is 2, url must
if action_type == 2:
if not isinstance(url, str):
raise ValueError(
"ClickAction.url must when ClickAction.type is 2")
if not url.upper().startswith("HTTPS"):
raise ValueError(
"ClickAction.url must be https prefix when ClickAction.type is 2"
)
@classmethod
def check_light_settings(
cls,
color,
light_on_duration,
light_off_duration,
):
cls.check_type(
color,
AndroidLightSettingsColor,
"color must be an instance of AndroidLightSettingsColor",
)
cls.check_string(
hint="AndroidLightSettings.light_on_duration",
value=light_on_duration,
)
cls.check_string(
hint="AndroidLightSettings.light_off_duration",
value=light_off_duration,
)
@classmethod
def check_light_settings_color(cls, alpha, red, green, blue):
cls.check_number("AndroidLightSettingsColor.alpha", alpha)
cls.check_number("AndroidLightSettingsColor.red", red)
cls.check_number("AndroidLightSettingsColor.green", green)
cls.check_number("AndroidLightSettingsColor.blue", blue)
@classmethod
def check_webpush_config(cls, headers, data, notification, hms_options):
# headers
cls.check_type(
headers,
WebPushHeader,
"headers must be an instance of WebPushHeader",
)
cls.check_string(hint="WebPushConfig.headers", value=data)
cls.check_type(
notification,
WebPushNotification,
"notification must be an instance of WebPushNotification",
)
cls.check_type(
hms_options,
WebPushHMSOptions,
"hms_options must be an instance of WebPushHMSOptions",
)
@classmethod
def check_webpush_header(cls, ttl=None, urgency=None, topic=None):
cls.check_string(hint="WebPushHeader.ttl", value=ttl)
cls.check_string(hint="WebPushHeader.urgency", value=urgency)
cls.check_string(hint="WebPushHeader.topic", value=topic)
@classmethod
def check_webpush_notification(
cls,
title=None,
body=None,
icon=None,
actions=None,
badge=None,
data=None,
dir=None,
image=None,
lang=None,
renotify=None,
require_interaction=None,
silent=None,
tag=None,
timestamp=None,
vibrate=None,
):
cls.check_string(hint="WebPushNotification.title", value=title)
cls.check_string(hint="WebPushNotification.body", value=body)
cls.check_string(hint="WebPushNotification.icon", value=icon)
cls.check_string(hint="WebPushNotification.data", value=data)
cls.check_type_list(
"WebPushNotificationAction.actions",
actions,
WebPushNotificationAction,
)
cls.check_string(hint="WebPushNotification.image", value=image)
cls.check_string(hint="WebPushNotification.lang", value=lang)
cls.check_string(hint="WebPushNotification.tag", value=tag)
cls.check_string(hint="WebPushNotification.badge", value=badge)
cls.assert_string_values(
"WebPushNotification.dir", dir, "auto", "ltr", "rtl")
cls.check_number_list("WebPushNotification.vibrate", vibrate)
cls.check_boolean("WebPushNotification.renotify", renotify)
cls.check_boolean(
"WebPushNotification.require_interaction", require_interaction
)
cls.check_boolean("WebPushNotification.silent", silent)
cls.check_number("WebPushNotification.timestamp", timestamp)
@classmethod
def check_webpush_notification_action(
cls,
action=None,
title=None,
icon=None,
):
cls.check_string(hint="WebPushNotificationAction.action", value=action)
cls.check_string(hint="WebPushNotificationAction.title", value=title)
cls.check_string(hint="WebPushNotificationAction.icon", value=icon)
@classmethod
def check_webpush_hms_options(cls, link):
cls.check_string(hint="WebPushHMSOptions.link", value=link)
@classmethod
def check_apns_config(
cls,
headers=None,
payload=None,
apns_hms_options=None,
):
cls.check_string_dict("APNsConfig.headers", headers)
cls.check_type(
payload,
APNsPayload,
"payload must be an instance of APNsPayload",
)
cls.check_type(
apns_hms_options,
APNsHMSOptions,
"apns_hms_options must be an instance of APNsHMSOptions",
)
@classmethod
def check_apns_payload(cls, aps=None):
cls.check_type(
aps,
APNsAps,
"aps must be an instance of APNsAps",
)
pass
@classmethod
def check_apns_payload_aps(
cls,
alert,
badge,
sound,
content_available,
category,
thread_id,
mutable_content,
custom_data,
):
# alert: Dictionary or String
if alert is not None:
if not isinstance(alert, six.string_types):
cls.check_type(
alert,
APNsAlert,
"alert must be an instance of String or APNsAlert class",
)
# badge: Number
cls.check_number("APNsAps.badge", badge)
# sound: String
cls.check_string("APNsAps.sound", sound)
# content_available: number
cls.check_number("APNsAps.content_available", content_available)
# category: String
cls.check_string("APNsAps.category", category)
# thread_id: String
cls.check_string("APNsAps.thread_id", thread_id)
# mutable_content
cls.check_boolean("APNsAps.mutable_content", mutable_content)
# custom_data
if custom_data is not None:
if not isinstance(custom_data, dict):
raise ValueError("APNsAps.custom_data must be a dict.")
@classmethod
def check_apns_payload_aps_alert(
cls,
title,
body,
loc_key,
loc_args,
title_loc_key,
title_loc_args,
action_loc_key,
launch_image,
custom_data,
):
# title: String
cls.check_string("APNsAlert.title", title)
# body: String
cls.check_string("APNsAlert.body", body)
# loc_key: String
cls.check_string("APNsAlert.loc_key", loc_key)
# loc_args: Array of strings
cls.check_string_list("APNsAlert.loc_args", loc_args)
# title_loc_key: String or null
cls.check_string("APNsAlert.title_loc_key", title_loc_key)
# title_loc_args: Array of strings or null
cls.check_string_list("APNsAlert.title_loc_args", title_loc_args)
# action_loc_key: String or null
cls.check_string("APNsAlert.action_loc_key", action_loc_key)
# launch_image: String
cls.check_string("APNsAlert.launch_image", launch_image)
# custom_data
if custom_data is not None:
if not isinstance(custom_data, dict):
raise ValueError("APNsAlert.custom_data must be a dict.")
@classmethod
def check_apns_hms_options(cls, target_user_type):
cls.assert_integer_values(
"APNsHMSOptions.target_user_type", target_user_type, 1, 2, 3
)