platform/realm/
validation.rs1use super::model::{Realm, RealmStatus};
6
7#[derive(Debug, Clone, PartialEq, Eq)]
12pub enum RealmValidationError {
13 RealmUnavailable { realm_id: u32, reason: String },
15 StoreError { realm_id: u32, message: String },
17}
18
19impl std::fmt::Display for RealmValidationError {
20 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
21 match self {
22 Self::RealmUnavailable { realm_id, reason } => {
23 write!(f, "Realm {realm_id} unavailable: {reason}")
24 }
25 Self::StoreError { realm_id, message } => {
26 write!(f, "Database error for realm {realm_id}: {message}")
27 }
28 }
29 }
30}
31
32impl std::error::Error for RealmValidationError {}
33
34impl Realm {
36 pub async fn validate_realm(realm_id: u32) -> Result<Realm, RealmValidationError> {
41 let realm = Self::get(realm_id)
42 .await
43 .map_err(|e| RealmValidationError::StoreError {
44 realm_id,
45 message: format!("Failed to query realm: {e}"),
46 })?;
47
48 let Some(realm) = realm else {
49 return Err(RealmValidationError::RealmUnavailable {
50 realm_id,
51 reason: format!("Realm {realm_id} not found"),
52 });
53 };
54
55 if realm.is_expired() {
56 return Err(RealmValidationError::RealmUnavailable {
57 realm_id,
58 reason: format!("Realm {realm_id} has expired"),
59 });
60 }
61
62 if realm.status != RealmStatus::Active {
63 return Err(RealmValidationError::RealmUnavailable {
64 realm_id,
65 reason: format!(
66 "Realm {} is not in Active status (current: {})",
67 realm_id, realm.status
68 ),
69 });
70 }
71
72 if !realm.enabled {
73 return Err(RealmValidationError::RealmUnavailable {
74 realm_id,
75 reason: format!("Realm {realm_id} is disabled"),
76 });
77 }
78
79 Ok(realm)
80 }
81
82 pub fn map_validation_error(err: RealmValidationError) -> (u32, String) {
88 match &err {
89 RealmValidationError::RealmUnavailable { reason, .. } => (403, reason.clone()),
90 RealmValidationError::StoreError { message, .. } => (500, message.clone()),
91 }
92 }
93}
94
95#[cfg(test)]
96mod tests {
97 use super::*;
98 use chrono::Utc;
99
100 #[test]
101 fn test_expiration_check() {
102 let realm = Realm {
103 expires_at: Some(Utc::now().timestamp() as u64 - 3600),
104 ..Default::default()
105 };
106 assert!(realm.is_expired());
107
108 let realm2 = Realm::default();
109 assert!(!realm2.is_expired());
110 }
111
112 #[test]
113 fn test_is_active() {
114 let realm = Realm {
115 expires_at: Some(Utc::now().timestamp() as u64 + 3600),
116 ..Default::default()
117 };
118 assert!(realm.is_active());
119
120 let realm2 = Realm {
121 expires_at: Some(Utc::now().timestamp() as u64 - 3600),
122 ..Default::default()
123 };
124 assert!(!realm2.is_active());
125
126 let realm3 = Realm {
127 status: RealmStatus::Suspended,
128 ..Default::default()
129 };
130 assert!(!realm3.is_active());
131 }
132
133 #[test]
134 fn test_validation_error_display() {
135 let err = RealmValidationError::RealmUnavailable {
136 realm_id: 1,
137 reason: "test reason".to_string(),
138 };
139 assert_eq!(err.to_string(), "Realm 1 unavailable: test reason");
140 assert_eq!(
141 Realm::map_validation_error(err),
142 (403, "test reason".to_string())
143 );
144
145 let err2 = RealmValidationError::StoreError {
146 realm_id: 2,
147 message: "timeout".to_string(),
148 };
149 assert_eq!(err2.to_string(), "Database error for realm 2: timeout");
150 assert_eq!(
151 Realm::map_validation_error(err2),
152 (500, "timeout".to_string())
153 );
154 }
155}