1use chrono::{DateTime, Utc};
6use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct AccessToken {
11 pub access_token: String,
13 pub token_type: String,
15 pub expires_in: u64,
17 pub created_at: DateTime<Utc>,
19}
20
21impl AccessToken {
22 pub fn new(access_token: String, token_type: String, expires_in: u64) -> Self {
24 Self {
25 access_token,
26 token_type,
27 expires_in,
28 created_at: Utc::now(),
29 }
30 }
31
32 pub fn is_expired(&self) -> bool {
34 let elapsed = Utc::now().signed_duration_since(self.created_at);
35 elapsed.num_seconds() >= (self.expires_in as i64 - 60) }
37
38 pub fn remaining_seconds(&self) -> i64 {
40 let elapsed = Utc::now().signed_duration_since(self.created_at);
41 (self.expires_in as i64) - elapsed.num_seconds()
42 }
43}
44
45#[derive(Debug, Clone, Serialize, Deserialize)]
47pub struct UserAccessToken {
48 pub access_token: String,
50 pub refresh_token: String,
52 pub token_type: String,
54 pub expires_in: u64,
56 pub refresh_expires_in: u64,
58 pub scope: String,
60 pub created_at: DateTime<Utc>,
62}
63
64impl UserAccessToken {
65 pub fn new(
67 access_token: String,
68 refresh_token: String,
69 token_type: String,
70 expires_in: u64,
71 refresh_expires_in: u64,
72 scope: String,
73 ) -> Self {
74 Self {
75 access_token,
76 refresh_token,
77 token_type,
78 expires_in,
79 refresh_expires_in,
80 scope,
81 created_at: Utc::now(),
82 }
83 }
84
85 pub fn is_access_token_expired(&self) -> bool {
87 let elapsed = Utc::now().signed_duration_since(self.created_at);
88 elapsed.num_seconds() >= (self.expires_in as i64 - 60) }
90
91 pub fn is_refresh_token_expired(&self) -> bool {
93 let elapsed = Utc::now().signed_duration_since(self.created_at);
94 elapsed.num_seconds() >= (self.refresh_expires_in as i64 - 60)
95 }
96
97 pub fn access_token_remaining_seconds(&self) -> i64 {
99 let elapsed = Utc::now().signed_duration_since(self.created_at);
100 (self.expires_in as i64) - elapsed.num_seconds()
101 }
102
103 pub fn refresh_token_remaining_seconds(&self) -> i64 {
105 let elapsed = Utc::now().signed_duration_since(self.created_at);
106 (self.refresh_expires_in as i64) - elapsed.num_seconds()
107 }
108}
109
110#[derive(Debug, Clone, Serialize, Deserialize)]
112pub struct TokenInfo {
113 pub content: serde_json::Value,
115 pub verified_at: DateTime<Utc>,
117}
118
119impl TokenInfo {
120 pub fn new(content: serde_json::Value) -> Self {
122 Self {
123 content,
124 verified_at: Utc::now(),
125 }
126 }
127}
128
129#[derive(Debug, Clone, Serialize, Deserialize)]
131pub struct UserInfo {
132 pub user_id: String,
134 pub name: String,
136 pub email: Option<String>,
138 pub mobile: Option<String>,
140 pub avatar: Option<String>,
142 pub department_ids: Option<Vec<String>>,
144 pub fetched_at: DateTime<Utc>,
146}
147
148impl UserInfo {
149 pub fn new(
151 user_id: String,
152 name: String,
153 email: Option<String>,
154 mobile: Option<String>,
155 avatar: Option<String>,
156 department_ids: Option<Vec<String>>,
157 ) -> Self {
158 Self {
159 user_id,
160 name,
161 email,
162 mobile,
163 avatar,
164 department_ids,
165 fetched_at: Utc::now(),
166 }
167 }
168}
169
170#[cfg(test)]
171#[allow(unused_imports)]
172mod tests {
173 use super::*;
174
175 #[test]
176 fn test_access_token_creation() {
177 let token = AccessToken::new(
178 "test_access_token".to_string(),
179 "Bearer".to_string(),
180 7200, );
182
183 assert_eq!(token.access_token, "test_access_token");
184 assert_eq!(token.token_type, "Bearer");
185 assert_eq!(token.expires_in, 7200);
186 assert!(!token.is_expired()); assert!(token.remaining_seconds() > 7000); }
189
190 #[test]
191 fn test_access_token_expiry() {
192 let token = AccessToken {
194 access_token: "expired_token".to_string(),
195 token_type: "Bearer".to_string(),
196 expires_in: 120, created_at: Utc::now() - chrono::Duration::seconds(61), };
199
200 assert!(token.is_expired());
201 assert!(token.remaining_seconds() <= 60);
203 }
204
205 #[test]
206 fn test_access_token_remaining_seconds() {
207 let token = AccessToken::new(
208 "test_token".to_string(),
209 "Bearer".to_string(),
210 3600, );
212
213 let remaining = token.remaining_seconds();
214 assert!(remaining > 3500); assert!(remaining <= 3600); }
217
218 #[test]
219 fn test_user_access_token_creation() {
220 let user_token = UserAccessToken::new(
221 "user_access_token".to_string(),
222 "refresh_token".to_string(),
223 "Bearer".to_string(),
224 7200, 2592000, "scope1 scope2".to_string(),
227 );
228
229 assert_eq!(user_token.access_token, "user_access_token");
230 assert_eq!(user_token.refresh_token, "refresh_token");
231 assert_eq!(user_token.token_type, "Bearer");
232 assert_eq!(user_token.expires_in, 7200);
233 assert_eq!(user_token.refresh_expires_in, 2592000);
234 assert_eq!(user_token.scope, "scope1 scope2");
235 assert!(!user_token.is_access_token_expired());
236 assert!(!user_token.is_refresh_token_expired());
237 }
238
239 #[test]
240 fn test_user_access_token_expiry() {
241 let user_token = UserAccessToken {
243 access_token: "expired_user_token".to_string(),
244 refresh_token: "refresh_token".to_string(),
245 token_type: "Bearer".to_string(),
246 expires_in: 120, refresh_expires_in: 180, scope: "test_scope".to_string(),
249 created_at: Utc::now() - chrono::Duration::seconds(121),
250 };
251
252 assert!(user_token.is_access_token_expired());
253 assert!(user_token.is_refresh_token_expired());
254 }
255
256 #[test]
257 fn test_user_access_token_remaining_seconds() {
258 let user_token = UserAccessToken::new(
259 "test_user_token".to_string(),
260 "refresh_token".to_string(),
261 "Bearer".to_string(),
262 3600, 7200, "scope".to_string(),
265 );
266
267 let access_remaining = user_token.access_token_remaining_seconds();
268 let refresh_remaining = user_token.refresh_token_remaining_seconds();
269
270 assert!(access_remaining > 3500 && access_remaining <= 3600);
271 assert!(refresh_remaining > 7000 && refresh_remaining <= 7200);
272 }
273
274 #[test]
275 fn test_token_info_creation() {
276 let content = serde_json::json!({
277 "user_id": "test_user",
278 "tenant_key": "test_tenant"
279 });
280
281 let token_info = TokenInfo::new(content.clone());
282
283 assert_eq!(token_info.content, content);
284 let now = Utc::now();
286 let time_diff = (now - token_info.verified_at).num_seconds().abs();
287 assert!(time_diff <= 1);
288 }
289
290 #[test]
291 fn test_user_info_creation() {
292 let departments = vec!["dept1".to_string(), "dept2".to_string()];
293 let user_info = UserInfo::new(
294 "user_123".to_string(),
295 "张三".to_string(),
296 Some("zhangsan@example.com".to_string()),
297 Some("+86 138 0013 8000".to_string()),
298 Some("https://example.com/avatar.jpg".to_string()),
299 Some(departments.clone()),
300 );
301
302 assert_eq!(user_info.user_id, "user_123");
303 assert_eq!(user_info.name, "张三");
304 assert_eq!(user_info.email, Some("zhangsan@example.com".to_string()));
305 assert_eq!(user_info.mobile, Some("+86 138 0013 8000".to_string()));
306 assert_eq!(
307 user_info.avatar,
308 Some("https://example.com/avatar.jpg".to_string())
309 );
310 assert_eq!(user_info.department_ids, Some(departments));
311
312 let now = Utc::now();
314 let time_diff = (now - user_info.fetched_at).num_seconds().abs();
315 assert!(time_diff <= 1);
316 }
317
318 #[test]
319 fn test_user_info_optional_fields() {
320 let user_info = UserInfo::new(
321 "user_456".to_string(),
322 "李四".to_string(),
323 None,
324 None,
325 None,
326 None,
327 );
328
329 assert_eq!(user_info.user_id, "user_456");
330 assert_eq!(user_info.name, "李四");
331 assert!(user_info.email.is_none());
332 assert!(user_info.mobile.is_none());
333 assert!(user_info.avatar.is_none());
334 assert!(user_info.department_ids.is_none());
335 }
336
337 #[test]
338 fn test_token_serialization() {
339 let token = AccessToken::new("test_token".to_string(), "Bearer".to_string(), 3600);
340
341 let json_str = serde_json::to_string(&token).unwrap();
343 let parsed: AccessToken = serde_json::from_str(&json_str).unwrap();
344
345 assert_eq!(parsed.access_token, token.access_token);
346 assert_eq!(parsed.token_type, token.token_type);
347 assert_eq!(parsed.expires_in, token.expires_in);
348 }
349
350 #[test]
351 fn test_user_token_serialization() {
352 let user_token = UserAccessToken::new(
353 "access_token".to_string(),
354 "refresh_token".to_string(),
355 "Bearer".to_string(),
356 3600,
357 7200,
358 "read write".to_string(),
359 );
360
361 let json_str = serde_json::to_string(&user_token).unwrap();
363 let parsed: UserAccessToken = serde_json::from_str(&json_str).unwrap();
364
365 assert_eq!(parsed.access_token, user_token.access_token);
366 assert_eq!(parsed.refresh_token, user_token.refresh_token);
367 assert_eq!(parsed.token_type, user_token.token_type);
368 assert_eq!(parsed.scope, user_token.scope);
369 }
370
371 #[test]
372 fn test_edge_case_expiry_times() {
373 let token = AccessToken::new(
375 "boundary_token".to_string(),
376 "Bearer".to_string(),
377 0, );
379
380 assert!(token.is_expired());
382
383 let negative_token =
385 AccessToken::new("negative_token".to_string(), "Bearer".to_string(), 0);
386 assert!(negative_token.is_expired());
387 }
388
389 #[test]
390 fn test_debug_formatting() {
391 let token = AccessToken::new("debug_token".to_string(), "Bearer".to_string(), 3600);
392
393 let debug_str = format!("{:?}", token);
394 assert!(debug_str.contains("AccessToken"));
395 assert!(debug_str.contains("debug_token"));
396 }
399
400 #[test]
401 fn test_clone_functionality() {
402 let original_token = AccessToken::new(
403 "clone_test_token".to_string(),
404 "Bearer".to_string(),
405 1800, );
407
408 let cloned_token = original_token.clone();
409 assert_eq!(original_token.access_token, cloned_token.access_token);
410 assert_eq!(original_token.token_type, cloned_token.token_type);
411 assert_eq!(original_token.expires_in, cloned_token.expires_in);
412 assert_eq!(original_token.created_at, cloned_token.created_at);
414
415 let original_user_token = UserAccessToken::new(
417 "user_access_token".to_string(),
418 "refresh_token".to_string(),
419 "Bearer".to_string(),
420 3600,
421 7200,
422 "read".to_string(),
423 );
424
425 let cloned_user_token = original_user_token.clone();
426 assert_eq!(
427 original_user_token.access_token,
428 cloned_user_token.access_token
429 );
430 assert_eq!(
431 original_user_token.refresh_token,
432 cloned_user_token.refresh_token
433 );
434 }
435}