use crate::database::{DbAccessToken, DbAuditLog, DbAuthCode, DbOAuthClient}; use crate::domain::models::*; use anyhow::Result; /// Trait for converting from database models to domain models pub trait FromDb { fn from_db(db_model: T) -> Result where Self: Sized; } /// Trait for converting from domain models to database models pub trait ToDb { fn to_db(&self) -> Result; } // OAuth Client conversions impl FromDb for OAuthClient { fn from_db(db_client: DbOAuthClient) -> Result { let redirect_uris: Vec = serde_json::from_str(&db_client.redirect_uris)?; let scopes: Vec = db_client .scopes .split_whitespace() .map(|s| s.to_string()) .collect(); let grant_types: Vec = db_client .grant_types .split_whitespace() .map(|s| s.to_string()) .collect(); let response_types: Vec = db_client .response_types .split_whitespace() .map(|s| s.to_string()) .collect(); Ok(OAuthClient { client_id: db_client.client_id, client_name: db_client.client_name, redirect_uris, scopes, grant_types, response_types, is_active: db_client.is_active, created_at: db_client.created_at, updated_at: db_client.updated_at, }) } } impl ToDb for OAuthClient { fn to_db(&self) -> Result { Ok(DbOAuthClient { id: 0, // Will be set by database client_id: self.client_id.clone(), client_secret_hash: String::new(), // Will be set separately client_name: self.client_name.clone(), redirect_uris: serde_json::to_string(&self.redirect_uris)?, scopes: self.scopes.join(" "), grant_types: self.grant_types.join(" "), response_types: self.response_types.join(" "), created_at: self.created_at, updated_at: self.updated_at, is_active: self.is_active, }) } } // Authorization Code conversions impl FromDb for AuthorizationCode { fn from_db(db_code: DbAuthCode) -> Result { let scopes = db_code .scope .map(|s| { s.split_whitespace() .map(|scope| scope.to_string()) .collect() }) .unwrap_or_default(); Ok(AuthorizationCode { code: db_code.code, client_id: db_code.client_id, user_id: db_code.user_id, redirect_uri: db_code.redirect_uri, scopes, expires_at: db_code.expires_at, created_at: db_code.created_at, is_used: db_code.is_used, code_challenge: db_code.code_challenge, code_challenge_method: db_code.code_challenge_method, }) } } impl ToDb for AuthorizationCode { fn to_db(&self) -> Result { let scope = if self.scopes.is_empty() { None } else { Some(self.scopes.join(" ")) }; Ok(DbAuthCode { id: 0, // Will be set by database code: self.code.clone(), client_id: self.client_id.clone(), user_id: self.user_id.clone(), redirect_uri: self.redirect_uri.clone(), scope, expires_at: self.expires_at, created_at: self.created_at, is_used: self.is_used, code_challenge: self.code_challenge.clone(), code_challenge_method: self.code_challenge_method.clone(), }) } } // Access Token conversions impl FromDb for AccessToken { fn from_db(db_token: DbAccessToken) -> Result { let scopes = db_token .scope .map(|s| { s.split_whitespace() .map(|scope| scope.to_string()) .collect() }) .unwrap_or_default(); Ok(AccessToken { token_id: db_token.token_id, client_id: db_token.client_id, user_id: db_token.user_id, scopes, expires_at: db_token.expires_at, created_at: db_token.created_at, is_revoked: db_token.is_revoked, }) } } impl ToDb for AccessToken { fn to_db(&self) -> Result { let scope = if self.scopes.is_empty() { None } else { Some(self.scopes.join(" ")) }; Ok(DbAccessToken { id: 0, // Will be set by database token_id: self.token_id.clone(), client_id: self.client_id.clone(), user_id: self.user_id.clone(), scope, expires_at: self.expires_at, created_at: self.created_at, is_revoked: self.is_revoked, token_hash: String::new(), // Will be set by service layer }) } } // Audit Event conversions impl FromDb for AuditEvent { fn from_db(db_log: DbAuditLog) -> Result { Ok(AuditEvent { event_type: db_log.event_type, client_id: db_log.client_id, user_id: db_log.user_id, ip_address: db_log.ip_address, user_agent: db_log.user_agent, details: db_log.details, success: db_log.success, timestamp: db_log.created_at, }) } } impl ToDb for AuditEvent { fn to_db(&self) -> Result { Ok(DbAuditLog { id: 0, // Will be set by database event_type: self.event_type.clone(), client_id: self.client_id.clone(), user_id: self.user_id.clone(), ip_address: self.ip_address.clone(), user_agent: self.user_agent.clone(), details: self.details.clone(), created_at: self.timestamp, success: self.success, }) } }