From 135dfb41e65797293b722973a8199788dad51e60 Mon Sep 17 00:00:00 2001 From: kdeterme Date: Fri, 4 Sep 2026 19:49:12 +0200 Subject: [PATCH] fix(webpush): support Django lazy translation objects in push payload JSON serialization --- loko/notifications/tests.py | 8 +++++--- loko/notifications/webpush.py | 20 +++++++++++--------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/loko/notifications/tests.py b/loko/notifications/tests.py index 77423bb..4cc21fa 100644 --- a/loko/notifications/tests.py +++ b/loko/notifications/tests.py @@ -312,14 +312,16 @@ class WebPushTests(TestCase): mock_resp = MagicMock() mock_resp.status_code = 201 + from django.utils.translation import gettext_lazy as _ with patch('notifications.webpush.requests.post', return_value=mock_resp) as mock_post: - send_webpush_to_user( + res = send_webpush_to_user( user=self.user, - title="Alerte Intervention", - body="Nouvelle intervention assignée", + title=_("Alerte Intervention"), + body=_("Nouvelle intervention assignée"), action_url="/interventions/1/", async_send=False ) + self.assertEqual(res.get('success'), 1) mock_post.assert_called_once() called_endpoint = mock_post.call_args[0][0] self.assertEqual(called_endpoint, sub.endpoint) diff --git a/loko/notifications/webpush.py b/loko/notifications/webpush.py index f4f7fed..bf44d17 100644 --- a/loko/notifications/webpush.py +++ b/loko/notifications/webpush.py @@ -12,7 +12,9 @@ from cryptography.hazmat.primitives.asymmetric import ec from cryptography.hazmat.primitives.ciphers.aead import AESGCM from cryptography.hazmat.primitives.kdf.hkdf import HKDF from django.conf import settings +from django.core.serializers.json import DjangoJSONEncoder from django.utils import timezone +from django.utils.encoding import force_str from py_vapid import Vapid, sign as vapid_sign import requests @@ -215,7 +217,7 @@ def _send_single_push(subscription: WebPushSubscription, payload: dict, vapid_ob receiver_pub_bytes = b64_urlsafe_decode(p256dh) auth_secret = b64_urlsafe_decode(auth) - payload_bytes = json.dumps(payload).encode('utf-8') + payload_bytes = json.dumps(payload, cls=DjangoJSONEncoder).encode('utf-8') encrypted_body = encrypt_webpush_rfc8291(payload_bytes, receiver_pub_bytes, auth_secret) vapid_headers = get_vapid_headers(endpoint, vapid_obj) @@ -276,14 +278,14 @@ def send_webpush_to_user( return {'success': 0, 'failed': 0, 'errors': ['Clé VAPID non configurée']} payload = { - 'title': title, - 'body': body or '', + 'title': force_str(title), + 'body': force_str(body or ''), 'icon': icon or '/static/common/android-192.png', 'badge': badge or '/static/common/favicon-48.png', - 'action_url': action_url or '/notifications/', + 'action_url': force_str(action_url or '/notifications/'), 'tag': tag or f"loko-{int(timezone.now().timestamp())}", 'data': { - 'url': action_url or '/notifications/', + 'url': force_str(action_url or '/notifications/'), **(extra_data or {}), }, } @@ -336,14 +338,14 @@ def send_webpush_to_users( return {'success': 0, 'failed': 0, 'errors': ['Clé VAPID non configurée']} payload = { - 'title': title, - 'body': body or '', + 'title': force_str(title), + 'body': force_str(body or ''), 'icon': icon or '/static/common/android-192.png', 'badge': badge or '/static/common/favicon-48.png', - 'action_url': action_url or '/notifications/', + 'action_url': force_str(action_url or '/notifications/'), 'tag': tag or f"loko-{int(timezone.now().timestamp())}", 'data': { - 'url': action_url or '/notifications/', + 'url': force_str(action_url or '/notifications/'), **(extra_data or {}), }, }