Skip to content

Commit 47345a1

Browse files
authored
FCM Options Support in WebpushConfig API (#242)
* Splitting messaging module into 2 files * Supporing WebpushFcmOptions API * Updated comment
1 parent 3446479 commit 47345a1

File tree

4 files changed

+86
-5
lines changed

4 files changed

+86
-5
lines changed

CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Unreleased
22

3+
- `messaging.WebpushConfig` class now supports configuring additional
4+
FCM options for the features supported by the web SDK. A new
5+
`messaging.WebpushFcmOptions` type has been introduced for this
6+
purpose.
37
- `messaging.Aps` class now supports configuring a critical sound. A new
48
`messaging.CriticalSound` class has been introduced for this purpose.
59
- [changed] Dropped support for Python 3.3.
@@ -24,7 +28,7 @@
2428
receiving realtime update events from the Firebase Database.
2529
- [added] The `db.reference()` method now optionally takes a `url`
2630
parameter. This can be used to access multiple Firebase Databases
27-
in the same project more easily.
31+
in the same project more easily.
2832
- [added] The `messaging.WebpushNotification` type now supports
2933
additional parameters.
3034

firebase_admin/_messaging_utils.py

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -150,14 +150,16 @@ class WebpushConfig(object):
150150
data: A dictionary of data fields (optional). All keys and values in the dictionary must be
151151
strings. When specified, overrides any data fields set via ``Message.data``.
152152
notification: A ``messaging.WebpushNotification`` to be included in the message (optional).
153+
fcm_options: A ``messaging.WebpushFcmOptions`` to be included in the messsage (optional).
153154
154155
.. _Webpush Specification: https://tools.ietf.org/html/rfc8030#section-5
155156
"""
156157

157-
def __init__(self, headers=None, data=None, notification=None):
158+
def __init__(self, headers=None, data=None, notification=None, fcm_options=None):
158159
self.headers = headers
159160
self.data = data
160161
self.notification = notification
162+
self.fcm_options = fcm_options
161163

162164

163165
class WebpushNotificationAction(object):
@@ -232,6 +234,18 @@ def __init__(self, title=None, body=None, icon=None, actions=None, badge=None, d
232234
self.custom_data = custom_data
233235

234236

237+
class WebpushFcmOptions(object):
238+
"""Options for features provided by the FCM SDK for Web.
239+
240+
Args:
241+
link: The link to open when the user clicks on the notification. Must be an HTTPS URL
242+
(optional).
243+
"""
244+
245+
def __init__(self, link=None):
246+
self.link = link
247+
248+
235249
class APNSConfig(object):
236250
"""APNS-specific options that can be included in a message.
237251
@@ -503,7 +517,7 @@ def encode_android_notification(cls, notification):
503517

504518
@classmethod
505519
def encode_webpush(cls, webpush):
506-
"""Encodes an WebpushConfig instance into JSON."""
520+
"""Encodes a WebpushConfig instance into JSON."""
507521
if webpush is None:
508522
return None
509523
if not isinstance(webpush, WebpushConfig):
@@ -514,12 +528,13 @@ def encode_webpush(cls, webpush):
514528
'headers': _Validators.check_string_dict(
515529
'WebpushConfig.headers', webpush.headers),
516530
'notification': cls.encode_webpush_notification(webpush.notification),
531+
'fcmOptions': cls.encode_webpush_fcm_options(webpush.fcm_options),
517532
}
518533
return cls.remove_null_values(result)
519534

520535
@classmethod
521536
def encode_webpush_notification(cls, notification):
522-
"""Encodes an WebpushNotification instance into JSON."""
537+
"""Encodes a WebpushNotification instance into JSON."""
523538
if notification is None:
524539
return None
525540
if not isinstance(notification, WebpushNotification):
@@ -588,6 +603,20 @@ def encode_webpush_notification_actions(cls, actions):
588603
results.append(cls.remove_null_values(result))
589604
return results
590605

606+
@classmethod
607+
def encode_webpush_fcm_options(cls, options):
608+
"""Encodes a WebpushFcmOptions instance into JSON."""
609+
if options is None:
610+
return None
611+
result = {
612+
'link': _Validators.check_string('WebpushConfig.fcm_options.link', options.link),
613+
}
614+
result = cls.remove_null_values(result)
615+
link = result.get('link')
616+
if link is not None and not link.startswith('https://'):
617+
raise ValueError('WebpushFcmOptions.link must be a HTTPS URL.')
618+
return result
619+
591620
@classmethod
592621
def encode_apns(cls, apns):
593622
"""Encodes an APNSConfig instance into JSON."""

firebase_admin/messaging.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
'Notification',
4040
'TopicManagementResponse',
4141
'WebpushConfig',
42+
'WebpushFcmOptions',
4243
'WebpushNotification',
4344
'WebpushNotificationAction',
4445

@@ -58,6 +59,7 @@
5859
Message = _messaging_utils.Message
5960
Notification = _messaging_utils.Notification
6061
WebpushConfig = _messaging_utils.WebpushConfig
62+
WebpushFcmOptions = _messaging_utils.WebpushFcmOptions
6163
WebpushNotification = _messaging_utils.WebpushNotification
6264
WebpushNotificationAction = _messaging_utils.WebpushNotificationAction
6365

tests/test_messaging.py

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,7 @@ def test_webpush_config(self):
401401
topic='topic',
402402
webpush=messaging.WebpushConfig(
403403
headers={'h1': 'v1', 'h2': 'v2'},
404-
data={'k1': 'v1', 'k2': 'v2'}
404+
data={'k1': 'v1', 'k2': 'v2'},
405405
)
406406
)
407407
expected = {
@@ -420,6 +420,52 @@ def test_webpush_config(self):
420420
check_encoding(msg, expected)
421421

422422

423+
class TestWebpushFcmOptionsEncoder(object):
424+
425+
@pytest.mark.parametrize('data', NON_OBJECT_ARGS)
426+
def test_invalid_webpush_fcm_options(self, data):
427+
with pytest.raises(AttributeError):
428+
check_encoding(messaging.Message(
429+
topic='topic', webpush=messaging.WebpushConfig(fcm_options=data)))
430+
431+
@pytest.mark.parametrize('data', NON_STRING_ARGS)
432+
def test_invalid_link_type(self, data):
433+
options = messaging.WebpushFcmOptions(link=data)
434+
with pytest.raises(ValueError) as excinfo:
435+
check_encoding(messaging.Message(
436+
topic='topic', webpush=messaging.WebpushConfig(fcm_options=options)))
437+
expected = 'WebpushConfig.fcm_options.link must be a string.'
438+
assert str(excinfo.value) == expected
439+
440+
@pytest.mark.parametrize('data', ['', 'foo', 'http://example'])
441+
def test_invalid_link_format(self, data):
442+
options = messaging.WebpushFcmOptions(link=data)
443+
with pytest.raises(ValueError) as excinfo:
444+
check_encoding(messaging.Message(
445+
topic='topic', webpush=messaging.WebpushConfig(fcm_options=options)))
446+
expected = 'WebpushFcmOptions.link must be a HTTPS URL.'
447+
assert str(excinfo.value) == expected
448+
449+
def test_webpush_notification(self):
450+
msg = messaging.Message(
451+
topic='topic',
452+
webpush=messaging.WebpushConfig(
453+
fcm_options=messaging.WebpushFcmOptions(
454+
link='https://example',
455+
),
456+
)
457+
)
458+
expected = {
459+
'topic': 'topic',
460+
'webpush': {
461+
'fcmOptions': {
462+
'link': 'https://example',
463+
},
464+
},
465+
}
466+
check_encoding(msg, expected)
467+
468+
423469
class TestWebpushNotificationEncoder(object):
424470

425471
def _check_notification(self, notification):

0 commit comments

Comments
 (0)