Skip to main content

shared/domain/user/
model.rs

1use chrono::{DateTime, Utc};
2use mongodb::bson::Bson;
3use serde::{Deserialize, Serialize};
4use sqlx::FromRow;
5use utoipa::ToSchema;
6
7use crate::domain::query::IntoBsonDocument;
8
9use super::super::serde::{deserialize_datetime, deserialize_object_id_as_string};
10
11#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
12pub enum CreateUserOutcome {
13    Created(User),
14    AlreadyExists,
15}
16
17#[derive(Default, Debug, Clone, PartialEq, Eq, Deserialize, Serialize, FromRow, ToSchema)]
18#[schema(example = json!({"id": Some(String::default()), "username": String::default(), "email": String::default(), "created_at": "2026-02-19T22:42:23.467Z"}))]
19pub struct User {
20    #[serde(
21        rename = "_id",
22        default,
23        skip_serializing_if = "Option::is_none",
24        deserialize_with = "deserialize_object_id_as_string"
25    )]
26    pub id: Option<String>,
27
28    pub username: String,
29    pub email: String,
30
31    #[sqlx(rename = "createdAt")]
32    #[serde(rename = "createdAt", deserialize_with = "deserialize_datetime")]
33    pub created_at: DateTime<Utc>,
34}
35
36impl User {
37    pub fn new() -> Self {
38        Self {
39            created_at: Utc::now(),
40            ..Default::default()
41        }
42    }
43    pub fn from_request(user: User) -> Self {
44        user
45    }
46}
47impl User {
48    pub fn with_id(&mut self, id: &str) {
49        self.id = Some(id.into());
50    }
51    pub fn with_username(mut self, username: &str) -> Self {
52        self.username = username.into();
53        self
54    }
55    pub fn with_email(mut self, email: &str) -> Self {
56        self.email = email.into();
57        self
58    }
59}
60impl User {
61    pub fn id(&self) -> Result<&str, crate::error::CoreError> {
62        self.id.as_deref().ok_or_else(|| {
63            tracing::error!(
64                error_code = "ValidationError::Malformed",
65                "Unexpected null/missing data"
66            );
67            crate::error::CoreError::Validation(crate::error::ValidationError::Malformed {
68                field: crate::error::CredentialField::ObjectId,
69            })
70        })
71    }
72}
73
74impl IntoBsonDocument for User {
75    fn into_bson_document(self) -> Result<mongodb::bson::Document, mongodb::bson::ser::Error> {
76        let mut doc = mongodb::bson::to_document(&self)?;
77
78        for key in &["createdAt"] {
79            if let Some(Bson::String(s)) = doc.get(*key).cloned()
80                && let Ok(dt) = DateTime::parse_from_rfc3339(&s)
81            {
82                doc.insert(
83                    *key,
84                    Bson::DateTime(mongodb::bson::DateTime::from_millis(dt.timestamp_millis())),
85                );
86            }
87        }
88
89        Ok(doc)
90    }
91}