use api::pagination::{Page, PageQuery}; use models::users::user_notifications; use models::users::user_notifications::NotificationType; use sea_orm::{ColumnTrait, EntityTrait, PaginatorTrait, QueryFilter, QueryOrder, QuerySelect}; use serde::{Deserialize, Serialize}; use serde_json::Value as JsonValue; use time::OffsetDateTime; use uuid::Uuid; use crate::AuthService; use crate::errors::AuthBusinessError; #[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: i64, page: PageQuery, notification_type: Option, unread: Option, ) -> Result, AuthBusinessError> { let (limit, offset) = page.bounds()?; let mut query = user_notifications::Entity::find().filter(user_notifications::Column::UserId.eq(uid)); 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 total = query.clone().count(self.db().read()).await?; let rows = query .order_by_desc(user_notifications::Column::CreatedAt) .limit(limit) .offset(offset) .all(self.db().read()) .await?; let items = 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(); Ok(Page::new(items, total, limit, offset)) } pub async fn unread_notifications_count(&self, uid: i64) -> 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_notifications_read( &self, uid: i64, 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: i64) -> Result<(), AuthBusinessError> { 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: i64, id: Uuid) -> Result<(), AuthBusinessError> { 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(AuthBusinessError::NotFound); } Ok(()) } }