use uuid::Uuid; use chrono::{DateTime, Utc}; use sqlx::{PgPool, FromRow}; use serde::Serialize; use crate::http_error::HttpError; #[derive(FromRow)] pub struct User { id: Uuid, session_token: Uuid, name: String, email: String, pass_hash: String, tokens: u64, created_at: DateTime } #[derive(Serialize)] pub struct ResponseUser { id: String, name: String, email: String } impl User { pub fn new(name: String, email: String, pass_hash: String) -> Self { Self { id: Uuid::now_v7(), session_token: Uuid::new_v4(), name: name, email: email.to_lowercase(), pass_hash: pass_hash, tokens: 0, created_at: Utc::now() } } pub async fn insert_one(&self, db: &PgPool) -> Result<(), HttpError> { let result = sqlx::query( "INSERT into users(id, session_token, name, email, pass_hash, tokens, created_at) VALUES($1, $2, $3, $4, $5, $6, $7)" ) .bind(&self.id) .bind(&self.session_token) .bind(&self.name) .bind(&self.email) .bind(&self.pass_hash) .bind(&self.tokens) .bind(&self.created_at) .execute(db) .await; match result { Ok(_) => Ok(()), Err(sqlx::Error::Database(db_err)) if db_err.code().as_deref() == Some("23505") => { Err(HttpError::InvalidInput("User with this email already exists".into())) }, Err(e) => Err(HttpError::Database(e.into())) } } pub async fn find_one_by_session( db: &PgPool, user_id: Uuid, session_token: Uuid ) -> Result { let user = sqlx::query_as::<_, User>( "SELECT * FROM users WHERE id = $1 and session_token = $2" ) .bind(user_id) .bind(session_token) .fetch_one(db) .await?; Ok(user) } pub fn response(self) -> ResponseUser { ResponseUser { id: self.id.to_string(), name: self.name, email: self.email } } }