feat: auth
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
use axum::{response::IntoResponse, Extension, Json};
|
||||
|
||||
use super::{mutation_login, AuthLoginRequestDto};
|
||||
use super::{
|
||||
mutation_login, mutation_register, AuthLoginRequestDto, AuthRegisterRequestDto,
|
||||
};
|
||||
use crate::AppState;
|
||||
use axum::{response::IntoResponse, Extension, Json};
|
||||
|
||||
pub async fn post_login(
|
||||
Extension(state): Extension<AppState>,
|
||||
@@ -9,3 +10,10 @@ pub async fn post_login(
|
||||
) -> impl IntoResponse {
|
||||
mutation_login(payload, &state).await
|
||||
}
|
||||
|
||||
pub async fn post_register(
|
||||
Extension(state): Extension<AppState>,
|
||||
Json(payload): Json<AuthRegisterRequestDto>,
|
||||
) -> impl IntoResponse {
|
||||
mutation_register(payload, &state).await
|
||||
}
|
||||
|
||||
@@ -8,10 +8,14 @@ pub struct AuthLoginRequestDto {
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)]
|
||||
pub struct AuthRegisterRequestDto {
|
||||
pub email: String,
|
||||
pub password: String,
|
||||
pub fullname: String,
|
||||
pub struct AuthLoginResponsetDto {
|
||||
pub token: TokenDto,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)]
|
||||
pub struct TokenDto {
|
||||
pub access_token: String,
|
||||
pub refresh_token: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)]
|
||||
|
||||
@@ -1,107 +1,32 @@
|
||||
use super::{auth_dto::AuthLoginRequestDto, AuthRegisterRequestDto};
|
||||
use crate::{
|
||||
common_response, hash_password, success_response, v1::UsersItemDto, AppState,
|
||||
ResponseSuccessDto,
|
||||
};
|
||||
use axum::{http::StatusCode, response::Response};
|
||||
use serde_json;
|
||||
use crate::{v1::UsersItemDto, AppState};
|
||||
use std::error::Error;
|
||||
|
||||
const USERS_KEY: &str = "users";
|
||||
use super::AuthRegisterRequestDto;
|
||||
|
||||
pub async fn mutation_login(
|
||||
params: AuthLoginRequestDto,
|
||||
pub async fn query_user_by_email(
|
||||
email: String,
|
||||
state: &AppState,
|
||||
) -> Response {
|
||||
let user: Option<AuthLoginRequestDto> = match state
|
||||
.surrealdb
|
||||
.select((USERS_KEY, params.email.as_str()))
|
||||
.await
|
||||
{
|
||||
Ok(user) => user,
|
||||
Err(err) => {
|
||||
return common_response(
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
&err.to_string(),
|
||||
);
|
||||
}
|
||||
};
|
||||
) -> Result<UsersItemDto, Box<dyn Error>> {
|
||||
let db = &state.surrealdb;
|
||||
|
||||
let mut redis_conn = match state.redisdb.get_connection() {
|
||||
Ok(conn) => conn,
|
||||
Err(err) => {
|
||||
return common_response(
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
&err.to_string(),
|
||||
);
|
||||
}
|
||||
};
|
||||
let mut result = db
|
||||
.query("SELECT * FROM app_users WHERE email = $email LIMIT 1;")
|
||||
.bind(("email", email.clone()))
|
||||
.await?;
|
||||
|
||||
let user_json = match serde_json::to_string(&user) {
|
||||
Ok(json) => json,
|
||||
Err(err) => {
|
||||
return common_response(
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
&err.to_string(),
|
||||
);
|
||||
}
|
||||
};
|
||||
let user: Option<UsersItemDto> = result.take(0)?;
|
||||
|
||||
if let Err(err) = redis::cmd("SET")
|
||||
.arg("users_data")
|
||||
.arg(user_json)
|
||||
.query::<()>(&mut redis_conn)
|
||||
{
|
||||
return common_response(StatusCode::INTERNAL_SERVER_ERROR, &err.to_string());
|
||||
}
|
||||
|
||||
let response = ResponseSuccessDto { data: params };
|
||||
|
||||
success_response(response)
|
||||
user.ok_or_else(|| format!("User not found for email: {}", email).into())
|
||||
}
|
||||
|
||||
pub async fn mutation_register(
|
||||
params: AuthRegisterRequestDto,
|
||||
pub async fn query_create_user(
|
||||
data: AuthRegisterRequestDto,
|
||||
state: &AppState,
|
||||
) -> Response {
|
||||
let user_key = format!("{}:{}", USERS_KEY, params.email);
|
||||
) -> Result<String, Box<dyn Error>> {
|
||||
let db = &state.surrealdb;
|
||||
|
||||
let existing_user: Option<UsersItemDto> =
|
||||
match state.surrealdb.select(&user_key).await {
|
||||
Ok(user) => user,
|
||||
Err(err) => {
|
||||
return common_response(
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
&err.to_string(),
|
||||
);
|
||||
}
|
||||
};
|
||||
let _record: Option<UsersItemDto> =
|
||||
db.create(("app_users", &data.email)).content(data).await?;
|
||||
|
||||
if existing_user.is_some() {
|
||||
return common_response(StatusCode::CONFLICT, "User already exists");
|
||||
}
|
||||
|
||||
let hashed_password = hash_password(¶ms.password);
|
||||
|
||||
let created_user: AuthLoginRequestDto =
|
||||
match state.surrealdb.create(&user_key, ¶ms).await {
|
||||
Ok(user) => Some(user),
|
||||
Err(err) => {
|
||||
return common_response(
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
&err.to_string(),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
let user_json = match serde_json::to_string(&created_user) {
|
||||
Ok(json) => json,
|
||||
Err(err) => {
|
||||
return common_response(
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
&err.to_string(),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
common_response(StatusCode::CREATED, "Success Register User")
|
||||
Ok("Success create user".into())
|
||||
}
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
use axum::{http::StatusCode, response::Response};
|
||||
|
||||
use super::{
|
||||
query_create_user, query_user_by_email, AuthLoginRequestDto,
|
||||
AuthRegisterRequestDto,
|
||||
};
|
||||
use crate::{common_response, hash_password, verify_password, AppState};
|
||||
|
||||
pub async fn mutation_login(
|
||||
payload: AuthLoginRequestDto,
|
||||
state: &AppState,
|
||||
) -> Response {
|
||||
match query_user_by_email(payload.email, state).await {
|
||||
Ok(user) => {
|
||||
let is_password_correct =
|
||||
verify_password(&payload.password, &user.password).unwrap_or(false);
|
||||
|
||||
if is_password_correct {
|
||||
common_response(
|
||||
StatusCode::BAD_REQUEST,
|
||||
"Email or password not correct",
|
||||
);
|
||||
}
|
||||
|
||||
common_response(StatusCode::OK, "Success Login")
|
||||
}
|
||||
Err(err) => common_response(StatusCode::UNAUTHORIZED, &err.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn mutation_register(
|
||||
payload: AuthRegisterRequestDto,
|
||||
state: &AppState,
|
||||
) -> Response {
|
||||
if query_user_by_email(payload.email.clone(), state)
|
||||
.await
|
||||
.is_ok()
|
||||
{
|
||||
return common_response(StatusCode::BAD_REQUEST, "User already exists");
|
||||
}
|
||||
|
||||
let hashed_password = match hash_password(&payload.password) {
|
||||
Ok(hash) => hash,
|
||||
Err(_) => {
|
||||
return common_response(
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
"Failed to hash password",
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
let new_user = AuthRegisterRequestDto {
|
||||
email: payload.email,
|
||||
password: hashed_password,
|
||||
fullname: payload.fullname,
|
||||
};
|
||||
|
||||
match query_create_user(new_user, state).await {
|
||||
Ok(_) => common_response(StatusCode::CREATED, "Registration successful"),
|
||||
Err(err) => {
|
||||
common_response(StatusCode::INTERNAL_SERVER_ERROR, &err.to_string())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,10 +4,14 @@ pub mod auth_controller;
|
||||
pub mod auth_dto;
|
||||
pub mod auth_middleware;
|
||||
pub mod auth_repository;
|
||||
pub mod auth_service;
|
||||
|
||||
pub use auth_dto::*;
|
||||
pub use auth_repository::*;
|
||||
pub use auth_service::*;
|
||||
|
||||
pub fn auth_router() -> Router {
|
||||
Router::new().route("/login", post(auth_controller::post_login))
|
||||
Router::new()
|
||||
.route("/login", post(auth_controller::post_login))
|
||||
.route("/register", post(auth_controller::post_register))
|
||||
}
|
||||
|
||||
@@ -5,4 +5,5 @@ use utoipa::ToSchema;
|
||||
pub struct UsersItemDto {
|
||||
pub email: String,
|
||||
pub fullname: String,
|
||||
pub password: String,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user