use crate::push::{PushPayload, WebPushService}; use db::database::AppDatabase; use models::users::user_notification; use sea_orm::{ColumnTrait, EntityTrait, QueryFilter}; use std::sync::Arc; use uuid::Uuid; /// Helper function to send push notification to a user. /// Reads the user's push subscription from `user_notification` table. /// Non-blocking: failures are logged but don't affect the caller. pub async fn send_push_notification( push: &WebPushService, db: &AppDatabase, user_id: Uuid, payload: &PushPayload, ) -> Result<(), String> { let prefs = user_notification::Entity::find() .filter(user_notification::Column::User.eq(user_id)) .one(db) .await .map_err(|e| format!("Failed to read push subscription: {}", e))?; if let Some(prefs) = prefs { if prefs.push_enabled { if let Some(endpoint) = &prefs.push_subscription_endpoint { if let Some(p256dh) = &prefs.push_subscription_keys_p256dh { if let Some(auth) = &prefs.push_subscription_keys_auth { push.send(endpoint, p256dh, auth, payload) .await .map_err(|e| format!("WebPush send failed: {}", e))?; } } } } } Ok(()) } /// Spawn a background task to send push notification. /// Failures are logged but don't affect the caller. pub fn spawn_push_notification( push: Option>, db: AppDatabase, user_id: Uuid, payload: PushPayload, ) { tokio::spawn(async move { if let Some(push) = push { if let Err(e) = send_push_notification(&push, &db, user_id, &payload).await { tracing::warn!(user_id = %user_id, error = %e, "Push notification failed"); } } }); } /// Create a push notification callback for RoomService. pub fn create_push_notification_fn( push: Arc, db: AppDatabase, ) -> room::PushNotificationFn { Arc::new( move |user_id: Uuid, title: String, body: Option, url: Option| { let push = push.clone(); let db = db.clone(); let payload = PushPayload { title, body: body.unwrap_or_default(), url, icon: None, }; tokio::spawn(async move { if let Err(e) = send_push_notification(&push, &db, user_id, &payload).await { tracing::warn!(user_id = %user_id, error = %e, "Push notification failed"); } }); }, ) }