Skip to content

Commit cfff7d4

Browse files
committed
Merge branch 'master' into error-handling-revamp
2 parents 7974c05 + de4ee2d commit cfff7d4

File tree

5 files changed

+218
-51
lines changed

5 files changed

+218
-51
lines changed

firebase_admin/_messaging_utils.py

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ class Message(object):
3838
android: An instance of ``messaging.AndroidConfig`` (optional).
3939
webpush: An instance of ``messaging.WebpushConfig`` (optional).
4040
apns: An instance of ``messaging.ApnsConfig`` (optional).
41-
fcm_options: An instance of ``messaging.FcmOptions`` (optional).
41+
fcm_options: An instance of ``messaging.FCMOptions`` (optional).
4242
token: The registration token of the device to which the message should be sent (optional).
4343
topic: Name of the FCM topic to which the message should be sent (optional). Topic name
4444
may contain the ``/topics/`` prefix.
@@ -69,7 +69,7 @@ class MulticastMessage(object):
6969
android: An instance of ``messaging.AndroidConfig`` (optional).
7070
webpush: An instance of ``messaging.WebpushConfig`` (optional).
7171
apns: An instance of ``messaging.ApnsConfig`` (optional).
72-
fcm_options: An instance of ``messaging.FcmOptions`` (optional).
72+
fcm_options: An instance of ``messaging.FCMOptions`` (optional).
7373
"""
7474
def __init__(self, tokens, data=None, notification=None, android=None, webpush=None, apns=None,
7575
fcm_options=None):
@@ -114,7 +114,7 @@ class AndroidConfig(object):
114114
data: A dictionary of data fields (optional). All keys and values in the dictionary must be
115115
strings. When specified, overrides any data fields set via ``Message.data``.
116116
notification: A ``messaging.AndroidNotification`` to be included in the message (optional).
117-
fcm_options: A ``messaging.AndroidFcmOptions`` to be included in the message (optional).
117+
fcm_options: A ``messaging.AndroidFCMOptions`` to be included in the message (optional).
118118
"""
119119

120120
def __init__(self, collapse_key=None, priority=None, ttl=None, restricted_package_name=None,
@@ -174,7 +174,7 @@ def __init__(self, title=None, body=None, icon=None, color=None, sound=None, tag
174174
self.channel_id = channel_id
175175

176176

177-
class AndroidFcmOptions(object):
177+
class AndroidFCMOptions(object):
178178
"""Options for features provided by the FCM SDK for Android.
179179
180180
Args:
@@ -195,7 +195,7 @@ class WebpushConfig(object):
195195
data: A dictionary of data fields (optional). All keys and values in the dictionary must be
196196
strings. When specified, overrides any data fields set via ``Message.data``.
197197
notification: A ``messaging.WebpushNotification`` to be included in the message (optional).
198-
fcm_options: A ``messaging.WebpushFcmOptions`` instance to be included in the message
198+
fcm_options: A ``messaging.WebpushFCMOptions`` instance to be included in the message
199199
(optional).
200200
201201
.. _Webpush Specification: https://tools.ietf.org/html/rfc8030#section-5
@@ -280,7 +280,7 @@ def __init__(self, title=None, body=None, icon=None, actions=None, badge=None, d
280280
self.custom_data = custom_data
281281

282282

283-
class WebpushFcmOptions(object):
283+
class WebpushFCMOptions(object):
284284
"""Options for features provided by the FCM SDK for Web.
285285
286286
Args:
@@ -300,7 +300,7 @@ class APNSConfig(object):
300300
Args:
301301
headers: A dictionary of headers (optional).
302302
payload: A ``messaging.APNSPayload`` to be included in the message (optional).
303-
fcm_options: A ``messaging.APNSFcmOptions`` instance to be included in the message
303+
fcm_options: A ``messaging.APNSFCMOptions`` instance to be included in the message
304304
(optional).
305305
306306
.. _APNS Documentation: https://developer.apple.com/library/content/documentation\
@@ -396,10 +396,13 @@ class ApsAlert(object):
396396
action_loc_key: Key of the text in the app's string resources to use to localize the
397397
action button text (optional).
398398
launch_image: Image for the notification action (optional).
399+
custom_data: A dict of custom key-value pairs to be included in the ApsAlert dictionary
400+
(optional)
399401
"""
400402

401403
def __init__(self, title=None, subtitle=None, body=None, loc_key=None, loc_args=None,
402-
title_loc_key=None, title_loc_args=None, action_loc_key=None, launch_image=None):
404+
title_loc_key=None, title_loc_args=None, action_loc_key=None, launch_image=None,
405+
custom_data=None):
403406
self.title = title
404407
self.subtitle = subtitle
405408
self.body = body
@@ -409,9 +412,10 @@ def __init__(self, title=None, subtitle=None, body=None, loc_key=None, loc_args=
409412
self.title_loc_args = title_loc_args
410413
self.action_loc_key = action_loc_key
411414
self.launch_image = launch_image
415+
self.custom_data = custom_data
412416

413417

414-
class APNSFcmOptions(object):
418+
class APNSFCMOptions(object):
415419
"""Options for features provided by the FCM SDK for iOS.
416420
417421
Args:
@@ -423,7 +427,7 @@ def __init__(self, analytics_label=None):
423427
self.analytics_label = analytics_label
424428

425429

426-
class FcmOptions(object):
430+
class FCMOptions(object):
427431
"""Options for features provided by SDK.
428432
429433
Args:
@@ -533,15 +537,15 @@ def encode_android(cls, android):
533537

534538
@classmethod
535539
def encode_android_fcm_options(cls, fcm_options):
536-
"""Encodes a AndroidFcmOptions instance into a json."""
540+
"""Encodes an AndroidFCMOptions instance into a json."""
537541
if fcm_options is None:
538542
return None
539-
if not isinstance(fcm_options, AndroidFcmOptions):
543+
if not isinstance(fcm_options, AndroidFCMOptions):
540544
raise ValueError('AndroidConfig.fcm_options must be an instance of '
541-
'AndroidFcmOptions class.')
545+
'AndroidFCMOptions class.')
542546
result = {
543547
'analytics_label': _Validators.check_analytics_label(
544-
'AndroidFcmOptions.analytics_label', fcm_options.analytics_label),
548+
'AndroidFCMOptions.analytics_label', fcm_options.analytics_label),
545549
}
546550
result = cls.remove_null_values(result)
547551
return result
@@ -701,7 +705,7 @@ def encode_webpush_notification_actions(cls, actions):
701705

702706
@classmethod
703707
def encode_webpush_fcm_options(cls, options):
704-
"""Encodes a WebpushFcmOptions instance into JSON."""
708+
"""Encodes a WebpushFCMOptions instance into JSON."""
705709
if options is None:
706710
return None
707711
result = {
@@ -710,7 +714,7 @@ def encode_webpush_fcm_options(cls, options):
710714
result = cls.remove_null_values(result)
711715
link = result.get('link')
712716
if link is not None and not link.startswith('https://'):
713-
raise ValueError('WebpushFcmOptions.link must be a HTTPS URL.')
717+
raise ValueError('WebpushFCMOptions.link must be a HTTPS URL.')
714718
return result
715719

716720
@classmethod
@@ -744,14 +748,14 @@ def encode_apns_payload(cls, payload):
744748

745749
@classmethod
746750
def encode_apns_fcm_options(cls, fcm_options):
747-
"""Encodes an APNSFcmOptions instance into JSON."""
751+
"""Encodes an APNSFCMOptions instance into JSON."""
748752
if fcm_options is None:
749753
return None
750-
if not isinstance(fcm_options, APNSFcmOptions):
751-
raise ValueError('APNSConfig.fcm_options must be an instance of APNSFcmOptions class.')
754+
if not isinstance(fcm_options, APNSFCMOptions):
755+
raise ValueError('APNSConfig.fcm_options must be an instance of APNSFCMOptions class.')
752756
result = {
753757
'analytics_label': _Validators.check_analytics_label(
754-
'APNSFcmOptions.analytics_label', fcm_options.analytics_label),
758+
'APNSFCMOptions.analytics_label', fcm_options.analytics_label),
755759
}
756760
result = cls.remove_null_values(result)
757761
return result
@@ -837,6 +841,14 @@ def encode_aps_alert(cls, alert):
837841
if result.get('title-loc-args') and not result.get('title-loc-key'):
838842
raise ValueError(
839843
'ApsAlert.title_loc_key is required when specifying title_loc_args.')
844+
if alert.custom_data is not None:
845+
if not isinstance(alert.custom_data, dict):
846+
raise ValueError('ApsAlert.custom_data must be a dict.')
847+
for key, val in alert.custom_data.items():
848+
_Validators.check_string('ApsAlert.custom_data key', key)
849+
# allow specifying key override because Apple could update API so that key
850+
# could have unexpected value type
851+
result[key] = val
840852
return cls.remove_null_values(result)
841853

842854
@classmethod
@@ -887,14 +899,14 @@ def default(self, obj): # pylint: disable=method-hidden
887899

888900
@classmethod
889901
def encode_fcm_options(cls, fcm_options):
890-
"""Encodes an FcmOptions instance into JSON."""
902+
"""Encodes an FCMOptions instance into JSON."""
891903
if fcm_options is None:
892904
return None
893-
if not isinstance(fcm_options, FcmOptions):
894-
raise ValueError('Message.fcm_options must be an instance of FcmOptions class.')
905+
if not isinstance(fcm_options, FCMOptions):
906+
raise ValueError('Message.fcm_options must be an instance of FCMOptions class.')
895907
result = {
896908
'analytics_label': _Validators.check_analytics_label(
897-
'FcmOptions.analytics_label', fcm_options.analytics_label),
909+
'FCMOptions.analytics_label', fcm_options.analytics_label),
898910
}
899911
result = cls.remove_null_values(result)
900912
return result

firebase_admin/_token_gen.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@
5151
'acr', 'amr', 'at_hash', 'aud', 'auth_time', 'azp', 'cnf', 'c_hash',
5252
'exp', 'firebase', 'iat', 'iss', 'jti', 'nbf', 'nonce', 'sub'
5353
])
54-
METADATA_SERVICE_URL = ('http://metadata/computeMetadata/v1/instance/service-accounts/'
55-
'default/email')
54+
METADATA_SERVICE_URL = ('http://metadata.google.internal/computeMetadata/v1/instance/'
55+
'service-accounts/default/email')
5656

5757

5858
class _SigningProvider(object):

firebase_admin/messaging.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,17 +33,17 @@
3333

3434
__all__ = [
3535
'AndroidConfig',
36-
'AndroidFcmOptions',
36+
'AndroidFCMOptions',
3737
'AndroidNotification',
3838
'APNSConfig',
39-
'APNSFcmOptions',
39+
'APNSFCMOptions',
4040
'APNSPayload',
4141
'Aps',
4242
'ApsAlert',
4343
'BatchResponse',
4444
'CriticalSound',
4545
'ErrorInfo',
46-
'FcmOptions',
46+
'FCMOptions',
4747
'Message',
4848
'MulticastMessage',
4949
'Notification',
@@ -54,7 +54,7 @@
5454
'TopicManagementResponse',
5555
'UnregisteredError',
5656
'WebpushConfig',
57-
'WebpushFcmOptions',
57+
'WebpushFCMOptions',
5858
'WebpushNotification',
5959
'WebpushNotificationAction',
6060

@@ -67,20 +67,21 @@
6767

6868

6969
AndroidConfig = _messaging_utils.AndroidConfig
70-
AndroidFcmOptions = _messaging_utils.AndroidFcmOptions
70+
AndroidFCMOptions = _messaging_utils.AndroidFCMOptions
7171
AndroidNotification = _messaging_utils.AndroidNotification
7272
APNSConfig = _messaging_utils.APNSConfig
73-
APNSFcmOptions = _messaging_utils.APNSFcmOptions
73+
APNSFCMOptions = _messaging_utils.APNSFCMOptions
7474
APNSPayload = _messaging_utils.APNSPayload
7575
Aps = _messaging_utils.Aps
7676
ApsAlert = _messaging_utils.ApsAlert
7777
CriticalSound = _messaging_utils.CriticalSound
78-
FcmOptions = _messaging_utils.FcmOptions
78+
FCMOptions = _messaging_utils.FCMOptions
7979
Message = _messaging_utils.Message
8080
MulticastMessage = _messaging_utils.MulticastMessage
8181
Notification = _messaging_utils.Notification
8282
WebpushConfig = _messaging_utils.WebpushConfig
83-
WebpushFcmOptions = _messaging_utils.WebpushFcmOptions
83+
WebpushFCMOptions = _messaging_utils.WebpushFCMOptions
84+
WebpushFcmOptions = _messaging_utils.WebpushFCMOptions
8485
WebpushNotification = _messaging_utils.WebpushNotification
8586
WebpushNotificationAction = _messaging_utils.WebpushNotificationAction
8687

snippets/messaging/cloud_messaging.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,3 +220,72 @@ def unsubscribe_from_topic():
220220
# for the contents of response.
221221
print(response.success_count, 'tokens were unsubscribed successfully')
222222
# [END unsubscribe]
223+
224+
225+
def send_all():
226+
registration_token = 'YOUR_REGISTRATION_TOKEN'
227+
# [START send_all]
228+
# Create a list containing up to 100 messages.
229+
messages = [
230+
messaging.Message(
231+
notification=messaging.Notification('Price drop', '5% off all electronics'),
232+
token=registration_token,
233+
),
234+
# ...
235+
messaging.Message(
236+
notification=messaging.Notification('Price drop', '2% off all books'),
237+
topic='readers-club',
238+
),
239+
]
240+
241+
response = messaging.send_all(messages)
242+
# See the BatchResponse reference documentation
243+
# for the contents of response.
244+
print('{0} messages were sent successfully'.format(response.success_count))
245+
# [END send_all]
246+
247+
248+
def send_multicast():
249+
# [START send_multicast]
250+
# Create a list containing up to 100 registration tokens.
251+
# These registration tokens come from the client FCM SDKs.
252+
registration_tokens = [
253+
'YOUR_REGISTRATION_TOKEN_1',
254+
# ...
255+
'YOUR_REGISTRATION_TOKEN_N',
256+
]
257+
258+
message = messaging.MulticastMessage(
259+
data={'score': '850', 'time': '2:45'},
260+
tokens=registration_tokens,
261+
)
262+
response = messaging.send_multicast(message)
263+
# See the BatchResponse reference documentation
264+
# for the contents of response.
265+
print('{0} messages were sent successfully'.format(response.success_count))
266+
# [END send_multicast]
267+
268+
269+
def send_multicast_and_handle_errors():
270+
# [START send_multicast_error]
271+
# These registration tokens come from the client FCM SDKs.
272+
registration_tokens = [
273+
'YOUR_REGISTRATION_TOKEN_1',
274+
# ...
275+
'YOUR_REGISTRATION_TOKEN_N',
276+
]
277+
278+
message = messaging.MulticastMessage(
279+
data={'score': '850', 'time': '2:45'},
280+
tokens=registration_tokens,
281+
)
282+
response = messaging.send_multicast(message)
283+
if response.failure_count > 0:
284+
responses = response.responses
285+
failed_tokens = []
286+
for idx, resp in enumerate(responses):
287+
if not resp.success:
288+
# The order of responses corresponds to the order of the registration tokens.
289+
failed_tokens.append(registration_tokens[idx])
290+
print('List of tokens that caused failures: {0}'.format(failed_tokens))
291+
# [END send_multicast_error]

0 commit comments

Comments
 (0)