summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--server/src/models/auth.rs10
-rw-r--r--server/src/models/user.rs18
-rw-r--r--server/src/routes/auth.rs29
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)))
+}