use models::users::user_suspensions; use sea_orm::{ColumnTrait, Condition, EntityTrait, QueryFilter, QueryOrder}; use serde::{Deserialize, Serialize}; use time::OffsetDateTime; use uuid::Uuid; use super::AuthService; use crate::errors::AuthError; #[derive(Debug, Clone, Serialize, Deserialize, utoipa::ToSchema)] pub struct SuspensionDto { pub id: Uuid, pub suspension_type: String, pub reason: Option, pub starts_at: OffsetDateTime, pub ends_at: Option, } impl AuthService { pub async fn active_suspension(&self, uid: i64) -> Result, AuthError> { let now = OffsetDateTime::now_utc(); let Some(row) = user_suspensions::Entity::find() .filter(user_suspensions::Column::UserId.eq(uid)) .filter(user_suspensions::Column::RevokedAt.is_null()) .filter(user_suspensions::Column::StartsAt.lte(now)) .filter( Condition::any() .add(user_suspensions::Column::EndsAt.is_null()) .add(user_suspensions::Column::EndsAt.gt(now)), ) .order_by_desc(user_suspensions::Column::StartsAt) .one(self.db().read()) .await? else { return Ok(None); }; Ok(Some(SuspensionDto { id: row.id, suspension_type: match row.suspension_type { user_suspensions::SuspensionType::Temporary => "temporary", user_suspensions::SuspensionType::Permanent => "permanent", } .to_string(), reason: row.reason, starts_at: row.starts_at, ends_at: row.ends_at, })) } pub async fn assert_not_suspended(&self, uid: i64) -> Result<(), AuthError> { if self.active_suspension(uid).await?.is_some() { return Err(AuthError::Forbidden); } Ok(()) } }