use models::users::user_notifications; use models::users::user_notifications::NotificationType; use sea_orm::{ ActiveModelTrait, ColumnTrait, EntityTrait, IntoActiveModel, PaginatorTrait, QueryFilter, QueryOrder, QuerySelect, Set, }; use serde::{Deserialize, Serialize}; use serde_json::Value as JsonValue; use time::OffsetDateTime; use uuid::Uuid; use super::AuthService; use crate::errors::AuthError; #[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)] pub struct NotificationDto { pub id: Uuid, pub notification_type: NotificationType, pub title: String, pub body: Option, pub data: Option, pub actor_id: Option, pub read_at: Option, pub created_at: OffsetDateTime, } impl AuthService { pub async fn list_notifications( &self, uid: Uuid, limit: Option, offset: Option, notification_type: Option, unread: Option, ) -> Result, AuthError> { let max_limit = limit.unwrap_or(50).min(100); let mut query = user_notifications::Entity::find() .filter(user_notifications::Column::UserId.eq(uid)) .order_by_desc(user_notifications::Column::CreatedAt) .limit(max_limit); if let Some(offset) = offset { query = query.offset(offset); } if let Some(notification_type) = notification_type { query = query.filter(user_notifications::Column::NotificationType.eq(notification_type)); } if unread == Some(true) { query = query.filter(user_notifications::Column::ReadAt.is_null()); } let rows = query.all(self.db().read()).await?; Ok(rows .into_iter() .map(|row| NotificationDto { id: row.id, notification_type: row.notification_type, title: row.title, body: row.body, data: row.data_json, actor_id: row.actor_uid, read_at: row.read_at, created_at: row.created_at, }) .collect()) } pub async fn unread_notifications_count(&self, uid: Uuid) -> Result { let count = user_notifications::Entity::find() .filter(user_notifications::Column::UserId.eq(uid)) .filter(user_notifications::Column::ReadAt.is_null()) .count(self.db().read()) .await?; Ok(count) } pub async fn mark_notification_read(&self, uid: Uuid, id: Uuid) -> Result<(), AuthError> { let db = self.db(); let Some(row) = user_notifications::Entity::find() .filter(user_notifications::Column::Id.eq(id)) .filter(user_notifications::Column::UserId.eq(uid)) .one(db.write()) .await? else { return Err(AuthError::NotFound); }; let mut active = row.into_active_model(); active.read_at = Set(Some(OffsetDateTime::now_utc())); active.update(db.write()).await?; Ok(()) } pub async fn mark_notifications_read( &self, uid: Uuid, ids: Vec, ) -> Result { let db = self.db(); let result = user_notifications::Entity::update_many() .col_expr( user_notifications::Column::ReadAt, sea_orm::sea_query::Expr::value(OffsetDateTime::now_utc()), ) .filter(user_notifications::Column::UserId.eq(uid)) .filter(user_notifications::Column::Id.is_in(ids)) .filter(user_notifications::Column::ReadAt.is_null()) .exec(db.write()) .await?; Ok(result.rows_affected) } pub async fn mark_all_notifications_read(&self, uid: Uuid) -> Result<(), AuthError> { let db = self.db(); user_notifications::Entity::update_many() .col_expr( user_notifications::Column::ReadAt, sea_orm::sea_query::Expr::value(OffsetDateTime::now_utc()), ) .filter(user_notifications::Column::UserId.eq(uid)) .filter(user_notifications::Column::ReadAt.is_null()) .exec(db.write()) .await?; Ok(()) } pub async fn delete_notification(&self, uid: Uuid, id: Uuid) -> Result<(), AuthError> { let db = self.db(); let result = user_notifications::Entity::delete_many() .filter(user_notifications::Column::Id.eq(id)) .filter(user_notifications::Column::UserId.eq(uid)) .exec(db.write()) .await?; if result.rows_affected == 0 { return Err(AuthError::NotFound); } Ok(()) } }