Re-implement FCM relay after introducing firebase (#1121)
This PR changes how `FCMRelayView` handles push notifications from OSS instances, also changing how the mobile app backend sends push notifications.
This commit is contained in:
parent
2dcb25721e
commit
231c0f45a3
2 changed files with 84 additions and 22 deletions
|
|
@ -1,29 +1,72 @@
|
|||
# from firebase_admin.messaging import Message
|
||||
# from fcm_django.models import FCMDevice
|
||||
import logging
|
||||
|
||||
from fcm_django.models import FCMDevice
|
||||
from firebase_admin.messaging import APNSConfig, APNSPayload, Aps, ApsAlert, CriticalSound, Message
|
||||
from rest_framework import status
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
|
||||
REQUIRED_FIELDS = {"registration_ids", "notification", "data"}
|
||||
logger = logging.getLogger(__name__)
|
||||
logger.setLevel(logging.DEBUG)
|
||||
|
||||
|
||||
# TODO: update thie
|
||||
class FCMRelayView(APIView):
|
||||
# TODO: use public API authentication (then it would be required to connect to a cloud instance to use the app)
|
||||
authentication_classes = []
|
||||
permission_classes = []
|
||||
|
||||
def post(self, request):
|
||||
"""
|
||||
This view accepts requests from OSS instances of Grafana OnCall and forwards these requests to FCM.
|
||||
Requests will be sent with the FCM_API_KEY configured in server settings
|
||||
(see PUSH_NOTIFICATIONS_SETTINGS in settings/base.py)
|
||||
This view accepts push notifications from OSS instances and forwards these requests to FCM.
|
||||
Requests to this endpoint come from OSS instances: apps.mobile_app.tasks.send_push_notification_to_fcm_relay
|
||||
"""
|
||||
|
||||
if not REQUIRED_FIELDS.issubset(request.data.keys()):
|
||||
try:
|
||||
token = request.data["token"]
|
||||
data = request.data["data"]
|
||||
except KeyError:
|
||||
return Response(status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# registration_ids = request.data["registration_ids"]
|
||||
# data = {
|
||||
# **request.data["data"],
|
||||
# **request.data["notification"],
|
||||
# }
|
||||
message = Message(token=token, data=data, apns=get_apns(request.data))
|
||||
|
||||
# return FCMDevice.objects.send_message(Message(), False, ["registration_ids"])
|
||||
return "TODO:"
|
||||
logger.debug(f"Sending message to FCM: {message}")
|
||||
result = FCMDevice(registration_id=token).send_message(message)
|
||||
logger.debug(f"FCM response: {result}")
|
||||
|
||||
return Response(status=status.HTTP_200_OK)
|
||||
|
||||
|
||||
def get_apns(data):
|
||||
"""
|
||||
Create APNSConfig object from JSON payload from OSS instance.
|
||||
"""
|
||||
aps = data.get("apns", {}).get("payload", {}).get("aps", {})
|
||||
if not aps:
|
||||
return None
|
||||
|
||||
thread_id = aps.get("thread-id")
|
||||
badge = aps.get("badge")
|
||||
|
||||
alert = aps.get("alert")
|
||||
if isinstance(alert, dict):
|
||||
alert = ApsAlert(**alert)
|
||||
|
||||
sound = aps.get("sound")
|
||||
if isinstance(sound, dict):
|
||||
sound = CriticalSound(**sound)
|
||||
|
||||
# remove all keys from "aps" so it can be used for custom_data
|
||||
for key in ["thread-id", "badge", "alert", "sound"]:
|
||||
aps.pop(key, None)
|
||||
|
||||
return APNSConfig(
|
||||
payload=APNSPayload(
|
||||
aps=Aps(
|
||||
thread_id=thread_id,
|
||||
badge=badge,
|
||||
alert=alert,
|
||||
sound=sound,
|
||||
custom_data=aps,
|
||||
)
|
||||
)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
import json
|
||||
import logging
|
||||
|
||||
import requests
|
||||
from celery.utils.log import get_task_logger
|
||||
from django.conf import settings
|
||||
from fcm_django.models import FCMDevice
|
||||
|
|
@ -6,10 +10,12 @@ from firebase_admin.messaging import APNSConfig, APNSPayload, Aps, ApsAlert, Cri
|
|||
from apps.alerts.models import AlertGroup
|
||||
from apps.mobile_app.alert_rendering import get_push_notification_message
|
||||
from apps.user_management.models import User
|
||||
from common.api_helpers.utils import create_engine_url
|
||||
from common.custom_celery_tasks import shared_dedicated_queue_retry_task
|
||||
|
||||
MAX_RETRIES = 1 if settings.DEBUG else 10
|
||||
logger = get_task_logger(__name__)
|
||||
logger.setLevel(logging.DEBUG)
|
||||
|
||||
|
||||
@shared_dedicated_queue_retry_task(autoretry_for=(Exception,), retry_backoff=True, max_retries=MAX_RETRIES)
|
||||
|
|
@ -71,8 +77,6 @@ def notify_user_async(user_pk, alert_group_pk, notification_policy_pk, critical)
|
|||
|
||||
alert_body = f"Status: {status_verbose}, alerts: {alerts_count_str}"
|
||||
|
||||
# TODO: we should update this to check if FCM_RELAY is set and conditionally make a call here..
|
||||
|
||||
message = Message(
|
||||
token=device_to_notify.registration_id,
|
||||
data={
|
||||
|
|
@ -109,10 +113,25 @@ def notify_user_async(user_pk, alert_group_pk, notification_policy_pk, critical)
|
|||
),
|
||||
)
|
||||
|
||||
logger.info(f"Sending push notification with message: {message}; thread-id: {thread_id};")
|
||||
logger.debug(f"Sending push notification with message: {message}; thread-id: {thread_id};")
|
||||
|
||||
fcm_response = device_to_notify.send_message(message)
|
||||
if settings.LICENSE == settings.OPEN_SOURCE_LICENSE_NAME:
|
||||
response = send_push_notification_to_fcm_relay(message)
|
||||
logger.debug(f"FCM relay response: {response}")
|
||||
else:
|
||||
response = device_to_notify.send_message(message)
|
||||
# NOTE: we may want to further handle the response from FCM, but for now lets simply log it out
|
||||
# https://firebase.google.com/docs/cloud-messaging/http-server-ref#interpret-downstream
|
||||
logger.debug(f"FCM response: {response}")
|
||||
|
||||
# NOTE: we may want to further handle the response from FCM, but for now lets simply log it out
|
||||
# https://firebase.google.com/docs/cloud-messaging/http-server-ref#interpret-downstream
|
||||
logger.info(f"FCM response was: {fcm_response}")
|
||||
|
||||
def send_push_notification_to_fcm_relay(message):
|
||||
"""
|
||||
Send push notification to FCM relay on cloud instance: apps.mobile_app.fcm_relay.FCMRelayView
|
||||
"""
|
||||
url = create_engine_url("mobile_app/v1/fcm_relay", override_base=settings.GRAFANA_CLOUD_ONCALL_API_URL)
|
||||
|
||||
response = requests.post(url, json=json.loads(str(message)))
|
||||
response.raise_for_status()
|
||||
|
||||
return response
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue