Skip to main content

litellm_rs/storage/database/entities/
user.rs

1use sea_orm::Set;
2use sea_orm::entity::prelude::*;
3use serde::{Deserialize, Serialize};
4
5/// User database model
6#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
7#[sea_orm(table_name = "users")]
8pub struct Model {
9    /// User ID (UUID)
10    #[sea_orm(primary_key, auto_increment = false)]
11    pub id: Uuid,
12
13    /// Username (unique)
14    #[sea_orm(unique)]
15    pub username: String,
16
17    /// Email address (unique)
18    #[sea_orm(unique)]
19    pub email: String,
20
21    /// Password hash
22    pub password_hash: String,
23
24    /// Display name (optional)
25    pub display_name: Option<String>,
26
27    /// User role
28    pub role: String,
29
30    /// User status
31    pub status: String,
32
33    /// Email verification status
34    pub email_verified: bool,
35
36    /// Two-factor authentication enabled
37    pub two_factor_enabled: bool,
38
39    /// Last login timestamp
40    pub last_login_at: Option<DateTimeWithTimeZone>,
41
42    /// Creation timestamp
43    pub created_at: DateTimeWithTimeZone,
44
45    /// Last update timestamp
46    pub updated_at: DateTimeWithTimeZone,
47
48    /// Version for optimistic locking
49    pub version: i32,
50}
51
52/// User entity relations
53#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
54pub enum Relation {
55    /// Password reset tokens relation
56    #[sea_orm(has_many = "super::password_reset_token::Entity")]
57    PasswordResetTokens,
58
59    /// User sessions relation
60    #[sea_orm(has_many = "super::user_session::Entity")]
61    UserSessions,
62}
63
64impl Related<super::password_reset_token::Entity> for Entity {
65    fn to() -> RelationDef {
66        Relation::PasswordResetTokens.def()
67    }
68}
69
70impl Related<super::user_session::Entity> for Entity {
71    fn to() -> RelationDef {
72        Relation::UserSessions.def()
73    }
74}
75
76impl ActiveModelBehavior for ActiveModel {}
77
78// Conversion methods between SeaORM model and our domain model
79impl Model {
80    /// Convert SeaORM model to domain user model
81    pub fn to_domain_user(
82        &self,
83    ) -> crate::utils::error::gateway_error::Result<crate::core::models::user::types::User> {
84        use crate::core::models::user::preferences::UserPreferences;
85        use crate::core::models::user::types::{UserProfile, UserRole, UserStatus};
86        use crate::core::models::{Metadata, UsageStats};
87        use crate::utils::error::gateway_error::GatewayError;
88        use std::str::FromStr;
89
90        let metadata = Metadata {
91            id: self.id,
92            created_at: self.created_at.naive_utc().and_utc(),
93            updated_at: self.updated_at.naive_utc().and_utc(),
94            version: self.version as i64,
95            extra: std::collections::HashMap::new(),
96        };
97
98        let role = UserRole::from_str(&self.role)
99            .map_err(|_| GatewayError::Storage("Invalid persisted users.role enum".to_string()))?;
100        let status = match self.status.as_str() {
101            "active" => UserStatus::Active,
102            "inactive" => UserStatus::Inactive,
103            "pending" => UserStatus::Pending,
104            "suspended" => UserStatus::Suspended,
105            "deleted" => UserStatus::Deleted,
106            _ => {
107                return Err(GatewayError::Storage(
108                    "Invalid persisted users.status enum".to_string(),
109                ));
110            }
111        };
112
113        Ok(crate::core::models::user::types::User {
114            metadata,
115            username: self.username.clone(),
116            email: self.email.clone(),
117            display_name: self.display_name.clone(),
118            password_hash: self.password_hash.clone(),
119            role,
120            status,
121            team_ids: vec![],
122            preferences: UserPreferences::default(),
123            usage_stats: UsageStats::default(),
124            rate_limits: None,
125            last_login_at: self.last_login_at.map(|dt| dt.naive_utc().and_utc()),
126            email_verified: self.email_verified,
127            two_factor_enabled: self.two_factor_enabled,
128            profile: UserProfile::default(),
129        })
130    }
131
132    /// Convert domain user model to SeaORM active model
133    pub fn from_domain_user(user: &crate::core::models::user::types::User) -> ActiveModel {
134        ActiveModel {
135            id: Set(user.metadata.id),
136            username: Set(user.username.clone()),
137            email: Set(user.email.clone()),
138            password_hash: Set(user.password_hash.clone()),
139            display_name: Set(user.display_name.clone()),
140            role: Set(user.role.to_string()),
141            status: Set(match user.status {
142                crate::core::models::user::types::UserStatus::Active => "active".to_string(),
143                crate::core::models::user::types::UserStatus::Inactive => "inactive".to_string(),
144                crate::core::models::user::types::UserStatus::Pending => "pending".to_string(),
145                crate::core::models::user::types::UserStatus::Suspended => "suspended".to_string(),
146                crate::core::models::user::types::UserStatus::Deleted => "deleted".to_string(),
147            }),
148            email_verified: Set(user.email_verified),
149            two_factor_enabled: Set(user.two_factor_enabled),
150            last_login_at: Set(user.last_login_at.map(|dt| dt.into())),
151            created_at: Set(user.metadata.created_at.into()),
152            updated_at: Set(user.metadata.updated_at.into()),
153            version: Set(user.metadata.version as i32),
154        }
155    }
156}