shared/domain/refresh_token/
model.rs1use chrono::{DateTime, Utc};
2use mongodb::bson::{self, Bson};
3use serde::{Deserialize, Serialize};
4use sqlx::prelude::FromRow;
5
6use super::super::serde::{
7 deserialize_datetime, deserialize_object_id, deserialize_object_id_as_string,
8 deserialize_option_datetime, serialize_object_id_as_string,
9};
10use super::ports::query::IntoBsonDocument;
11
12#[derive(Default, Clone, Debug, PartialEq, Eq, Deserialize, Serialize, FromRow)]
13pub struct RefreshToken {
14 #[serde(
15 rename = "_id",
16 default,
17 skip_serializing_if = "Option::is_none",
18 deserialize_with = "deserialize_object_id_as_string"
19 )]
20 pub id: Option<String>,
21
22 #[sqlx(rename = "userId")]
23 #[serde(
24 rename = "userId",
25 default,
26 serialize_with = "serialize_object_id_as_string",
27 deserialize_with = "deserialize_object_id"
28 )]
29 pub user_id: String,
30
31 #[sqlx(rename = "issuedAt")]
32 #[serde(rename = "issuedAt", deserialize_with = "deserialize_datetime")]
33 pub issued_at: DateTime<Utc>,
34 #[sqlx(rename = "expiresAt")]
35 #[serde(rename = "expiresAt", deserialize_with = "deserialize_datetime")]
36 pub expires_at: DateTime<Utc>,
37 #[sqlx(rename = "usedAt")]
38 #[serde(rename = "usedAt", deserialize_with = "deserialize_option_datetime")]
39 pub used_at: Option<DateTime<Utc>>,
40
41 pub jti: String,
42}
43
44impl RefreshToken {
45 pub fn new(jti: &str) -> Self {
46 RefreshToken {
47 jti: jti.to_string(),
48 issued_at: chrono::Utc::now(),
49 ..Default::default()
50 }
51 }
52}
53impl RefreshToken {
54 pub fn with_user_id(mut self, id: &str) -> Self {
55 self.user_id = id.into();
56 self
57 }
58 pub fn with_expire_at(mut self, expires_in: i64) -> Self {
59 self.expires_at = chrono::Utc::now() + chrono::Duration::seconds(expires_in);
60 self
61 }
62}
63
64impl IntoBsonDocument for RefreshToken {
65 fn into_bson_document(self) -> Result<bson::Document, bson::ser::Error> {
66 let mut doc = bson::to_document(&self)?;
67
68 for key in &["expiresAt", "issuedAt", "usedAt"] {
69 if let Some(Bson::String(s)) = doc.get(*key).cloned()
70 && let Ok(dt) = DateTime::parse_from_rfc3339(&s)
71 {
72 doc.insert(
73 *key,
74 Bson::DateTime(bson::DateTime::from_millis(dt.timestamp_millis())),
75 );
76 }
77 }
78
79 Ok(doc)
80 }
81}
82
83#[derive(Debug, Serialize, Deserialize, Default)]
84pub struct IssuedTokens {
85 #[serde(rename = "accessToken")]
86 pub access_token: String,
87
88 #[serde(rename = "refreshToken")]
89 pub refresh_token: String,
90
91 #[serde(rename = "refreshTokenJti")]
92 pub refresh_token_jti: String,
93}
94impl IssuedTokens {
95 pub fn with_access_token(mut self, access_token: &str) -> Self {
96 self.access_token = access_token.into();
97 self
98 }
99
100 pub fn with_refresh_token(mut self, refresh_token: &str) -> Self {
101 self.refresh_token = refresh_token.into();
102 self
103 }
104
105 pub fn with_jti(mut self, jti: uuid::Uuid) -> Self {
106 self.refresh_token_jti = jti.to_string();
107 self
108 }
109}