shared/domain/user/
model.rs1use 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}