Skip to content
Clone
194c44c
137 lines 4.7 KB Rust
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<String>,
pub data: Option<JsonValue>,
pub actor_id: Option<i64>,
pub read_at: Option<OffsetDateTime>,
pub created_at: OffsetDateTime,
}
impl AuthService {
pub async fn list_notifications(
&self,
uid: i64,
limit: Option<u64>,
offset: Option<u64>,
notification_type: Option<NotificationType>,
unread: Option<bool>,
) -> Result<Vec<NotificationDto>, 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: i64) -> Result<u64, AuthError> {
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: i64, 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: i64,
ids: Vec<Uuid>,
) -> Result<u64, AuthError> {
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<(), 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: i64, 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(())
}
}