Files
MAIA/backend/modules/notifications/service.py
c-d-p 62d6b8bdfd [V1.0] Working application, added notifications.
Ready to upload to store.
2025-04-27 00:39:52 +02:00

112 lines
3.9 KiB
Python

import httpx
import logging
from typing import Optional, Dict, Any
from core.config import settings
logger = logging.getLogger(__name__)
async def send_push_notification(
push_token: str, title: str, body: str, data: Optional[Dict[str, Any]] = None
) -> bool:
"""
Sends a push notification to a specific Expo push token.
Args:
push_token: The recipient's Expo push token.
title: The title of the notification.
body: The main message content of the notification.
data: Optional dictionary containing extra data to send with the notification.
Returns:
True if the notification was sent successfully (according to Expo API), False otherwise.
"""
if not push_token:
logger.warning("Attempted to send notification but no push token provided.")
return False
message = {
"to": push_token,
"sound": "default",
"title": title,
"body": body,
"priority": "high",
"channelId": "default",
}
if data:
message["data"] = data
async with httpx.AsyncClient() as client:
try:
response = await client.post(
settings.EXPO_PUSH_API_URL,
headers={
"Accept": "application/json",
"Accept-Encoding": "gzip, deflate",
"Content-Type": "application/json",
},
json=message,
timeout=10.0,
)
response.raise_for_status() # Raise exception for 4xx/5xx responses
response_data = response.json()
logger.debug(f"Expo push API response: {response_data}")
# Check for top-level errors first
if "errors" in response_data:
error_messages = [
err.get("message", "Unknown error")
for err in response_data["errors"]
]
logger.error(
f"Expo API returned errors for {push_token[:10]}...: {'; '.join(error_messages)}"
)
return False
# Check the status in the data field
receipt = response_data.get("data")
# if receipts is a list
if receipt:
status = receipt.get("status")
if status == "ok":
logger.info(
f"Successfully sent push notification to token: {push_token[:10]}..."
)
return True
else:
# Log details if the status is not 'ok'
error_details = receipt.get("details")
error_message = receipt.get("message")
logger.error(
f"Failed to send push notification to {push_token[:10]}... "
f"Expo status: {status}, Message: {error_message}, Details: {error_details}"
)
return False
else:
# Log if 'data' is missing, not a list, or an empty list
logger.error(
f"Unexpected Expo API response format or empty 'data' field for {push_token[:10]}... "
f"Response: {response_data}"
)
return False
except httpx.HTTPStatusError as e:
logger.error(
f"HTTP error sending push notification to {push_token[:10]}...: {e.response.status_code} - {e.response.text}"
)
return False
except httpx.RequestError as e:
logger.error(
f"Network error sending push notification to {push_token[:10]}...: {e}"
)
return False
except Exception as e:
logger.exception(
f"Unexpected error sending push notification to {push_token[:10]}...: {e}"
)
return False