gitdataai/libs/service/user/notification.rs
2026-04-14 19:02:01 +08:00

201 lines
7.7 KiB
Rust

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<bool>,
pub in_app_enabled: Option<bool>,
pub push_enabled: Option<bool>,
pub digest_mode: Option<String>,
pub dnd_enabled: Option<bool>,
pub dnd_start_minute: Option<i32>,
pub dnd_end_minute: Option<i32>,
pub marketing_enabled: Option<bool>,
pub security_enabled: Option<bool>,
pub product_enabled: Option<bool>,
}
#[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<i32>,
pub dnd_end_minute: Option<i32>,
pub marketing_enabled: bool,
pub security_enabled: bool,
pub product_enabled: bool,
pub created_at: chrono::DateTime<Utc>,
pub updated_at: chrono::DateTime<Utc>,
}
impl From<user_notification::Model> 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<NotificationPreferencesResponse, AppError> {
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<NotificationPreferencesResponse, AppError> {
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<NotificationPreferencesResponse, AppError> {
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))
}
}