diff options
Diffstat (limited to 'server')
-rw-r--r-- | server/src/models/auth.rs | 10 | ||||
-rw-r--r-- | server/src/models/user.rs | 18 | ||||
-rw-r--r-- | server/src/routes/auth.rs | 29 |
3 files changed, 53 insertions, 4 deletions
diff --git a/server/src/models/auth.rs b/server/src/models/auth.rs index 8b8f61c..1e466d3 100644 --- a/server/src/models/auth.rs +++ b/server/src/models/auth.rs @@ -18,7 +18,7 @@ struct Keys { #[derive(Serialize, Deserialize)] pub struct Claims { /// ID from the user model - user_id: i32, + pub user_id: i32, /// Expiration timestamp exp: usize, } @@ -32,6 +32,14 @@ pub struct AuthBody { token_type: String, } +/// Paylod used for user creation +#[derive(Deserialize)] +pub struct SignUpForm { + pub email: String, + pub password1: String, + pub password2: String, +} + static KEYS: Lazy<Keys> = Lazy::new(|| { let secret = std::env::var("JWT_SECRET").expect("JWT_SECRET must be set"); Keys::new(secret.as_bytes()) diff --git a/server/src/models/user.rs b/server/src/models/user.rs index 06cde0a..b94e114 100644 --- a/server/src/models/user.rs +++ b/server/src/models/user.rs @@ -3,6 +3,7 @@ use crate::errors::AppError; use serde::{Deserialize, Serialize}; use validator::Validate; +use sqlx::Row; /// User model #[derive(Deserialize, Serialize, Validate)] @@ -115,4 +116,21 @@ impl User { Ok(rows) } + + /// Prevent the "uniquess" Postgres fields check. Check if email has been taken + pub async fn email_has_taken(email: &String) -> Result<bool, AppError> { + let pool = unsafe { get_client() }; + let cursor = sqlx::query( + r#" + SELECT COUNT(id) as count FROM users WHERE email = $1 + "#, + ) + .bind(email) + .fetch_one(pool) + .await?; + + let count: i64 = cursor.try_get(0).unwrap(); + + Ok(count > 0) + } } diff --git a/server/src/routes/auth.rs b/server/src/routes/auth.rs index 37c41b2..e3d7e4e 100644 --- a/server/src/routes/auth.rs +++ b/server/src/routes/auth.rs @@ -1,13 +1,15 @@ use crate::errors::AppError; use crate::models::{ - auth::{AuthBody, Claims}, - user::{User, UserCreate}, + auth::{AuthBody, Claims, SignUpForm}, + user::*, }; use axum::{routing::post, Json, Router}; /// Create routes for `/v1/auth/` namespace pub fn create_route() -> Router { - Router::new().route("/login", post(make_login)) + Router::new() + .route("/login", post(make_login)) + .route("/signup", post(signup)) } /// Make login. Check if a user with the email and password passed in request body exists into the @@ -23,3 +25,24 @@ async fn make_login(Json(payload): Json<UserCreate>) -> Result<Json<AuthBody>, A Err(_) => Err(AppError::NotFound), } } +/// Create a new user +async fn signup(Json(payload): Json<SignUpForm>) -> Result<Json<AuthBody>, AppError> { + if payload.password1 != payload.password2 { + return Err(AppError::BadRequest( + "The inserted passwords do not match".to_string(), + )); + } + + if User::email_has_taken(&payload.email).await? { + return Err(AppError::BadRequest( + "An user with this email already exists".to_string(), + )); + } + + let user = User::new(payload.email, payload.password1); + let user = User::create(user).await?; + + let claims = Claims::new(user.id); + let token = claims.get_token()?; + Ok(Json(AuthBody::new(token))) +} |