use crate::AppService; use crate::error::AppError; use chrono::Utc; use models::users::{user_activity_log, user_notification}; use sea_orm::*; use serde::{Deserialize, Serialize}; use session::Session; use uuid::Uuid; #[derive(Deserialize, Serialize, Clone, Debug, utoipa::ToSchema)] pub struct NotificationPreferencesParams { pub email_enabled: Option, pub in_app_enabled: Option, pub push_enabled: Option, pub digest_mode: Option, pub dnd_enabled: Option, pub dnd_start_minute: Option, pub dnd_end_minute: Option, pub marketing_enabled: Option, pub security_enabled: Option, pub product_enabled: Option, } #[derive(Deserialize, Serialize, Clone, Debug, utoipa::ToSchema)] pub struct NotificationPreferencesResponse { pub user_id: Uuid, pub email_enabled: bool, pub in_app_enabled: bool, pub push_enabled: bool, pub digest_mode: String, pub dnd_enabled: bool, pub dnd_start_minute: Option, pub dnd_end_minute: Option, pub marketing_enabled: bool, pub security_enabled: bool, pub product_enabled: bool, pub created_at: chrono::DateTime, pub updated_at: chrono::DateTime, } impl From for NotificationPreferencesResponse { fn from(prefs: user_notification::Model) -> Self { NotificationPreferencesResponse { user_id: prefs.user, email_enabled: prefs.email_enabled, in_app_enabled: prefs.in_app_enabled, push_enabled: prefs.push_enabled, digest_mode: prefs.digest_mode, dnd_enabled: prefs.dnd_enabled, dnd_start_minute: prefs.dnd_start_minute, dnd_end_minute: prefs.dnd_end_minute, marketing_enabled: prefs.marketing_enabled, security_enabled: prefs.security_enabled, product_enabled: prefs.product_enabled, created_at: prefs.created_at, updated_at: prefs.updated_at, } } } impl AppService { pub async fn user_get_notification_preferences( &self, context: &Session, ) -> Result { let user_uid = context.user().ok_or(AppError::Unauthorized)?; let prefs = user_notification::Entity::find_by_id(user_uid) .one(&self.db) .await?; if let Some(prefs) = prefs { Ok(NotificationPreferencesResponse::from(prefs)) } else { self.user_create_default_notification_preferences(user_uid) .await } } pub async fn user_update_notification_preferences( &self, context: &Session, params: NotificationPreferencesParams, ) -> Result { let user_uid = context.user().ok_or(AppError::Unauthorized)?; let prefs = user_notification::Entity::find_by_id(user_uid) .one(&self.db) .await?; let updated_prefs = if let Some(prefs) = prefs { let mut active_prefs: user_notification::ActiveModel = prefs.into(); if let Some(email_enabled) = params.email_enabled { active_prefs.email_enabled = Set(email_enabled); } if let Some(in_app_enabled) = params.in_app_enabled { active_prefs.in_app_enabled = Set(in_app_enabled); } if let Some(push_enabled) = params.push_enabled { active_prefs.push_enabled = Set(push_enabled); } if let Some(digest_mode) = params.digest_mode.clone() { active_prefs.digest_mode = Set(digest_mode); } if let Some(dnd_enabled) = params.dnd_enabled { active_prefs.dnd_enabled = Set(dnd_enabled); } if let Some(dnd_start_minute) = params.dnd_start_minute { active_prefs.dnd_start_minute = Set(Some(dnd_start_minute)); } if let Some(dnd_end_minute) = params.dnd_end_minute { active_prefs.dnd_end_minute = Set(Some(dnd_end_minute)); } if let Some(marketing_enabled) = params.marketing_enabled { active_prefs.marketing_enabled = Set(marketing_enabled); } if let Some(security_enabled) = params.security_enabled { active_prefs.security_enabled = Set(security_enabled); } if let Some(product_enabled) = params.product_enabled { active_prefs.product_enabled = Set(product_enabled); } active_prefs.updated_at = Set(Utc::now()); active_prefs.update(&self.db).await? } else { let new_prefs = user_notification::ActiveModel { user: Set(user_uid), email_enabled: Set(params.email_enabled.unwrap_or(true)), in_app_enabled: Set(params.in_app_enabled.unwrap_or(true)), push_enabled: Set(params.push_enabled.unwrap_or(false)), digest_mode: Set(params .digest_mode .clone() .unwrap_or_else(|| "daily".to_string())), dnd_enabled: Set(params.dnd_enabled.unwrap_or(false)), dnd_start_minute: Set(params.dnd_start_minute), dnd_end_minute: Set(params.dnd_end_minute), marketing_enabled: Set(params.marketing_enabled.unwrap_or(false)), security_enabled: Set(params.security_enabled.unwrap_or(true)), product_enabled: Set(params.product_enabled.unwrap_or(false)), created_at: Set(Utc::now()), updated_at: Set(Utc::now()), }; new_prefs.insert(&self.db).await? }; let _ = user_activity_log::ActiveModel { user_uid: Set(Some(user_uid)), action: Set("notification_preferences_update".to_string()), ip_address: Set(context.ip_address()), user_agent: Set(context.user_agent()), details: Set(serde_json::json!({ "updated_fields": { "email_enabled": params.email_enabled.is_some(), "in_app_enabled": params.in_app_enabled.is_some(), "push_enabled": params.push_enabled.is_some(), "digest_mode": params.digest_mode.is_some(), "dnd_enabled": params.dnd_enabled.is_some(), "marketing_enabled": params.marketing_enabled.is_some(), "security_enabled": params.security_enabled.is_some(), "product_enabled": params.product_enabled.is_some(), } })), created_at: Set(Utc::now()), ..Default::default() } .insert(&self.db) .await; Ok(NotificationPreferencesResponse::from(updated_prefs)) } async fn user_create_default_notification_preferences( &self, user_uid: Uuid, ) -> Result { let prefs = user_notification::ActiveModel { user: Set(user_uid), email_enabled: Set(true), in_app_enabled: Set(true), push_enabled: Set(false), digest_mode: Set("daily".to_string()), dnd_enabled: Set(false), dnd_start_minute: Set(None), dnd_end_minute: Set(None), marketing_enabled: Set(false), security_enabled: Set(true), product_enabled: Set(false), created_at: Set(Utc::now()), updated_at: Set(Utc::now()), }; let created_prefs = prefs.insert(&self.db).await?; Ok(NotificationPreferencesResponse::from(created_prefs)) } }