Files
msgs/src/api/login.rs
T
wt 9f0681563e
Continuous integration / Check (push) Successful in 42s
Continuous integration / Rustfmt (push) Successful in 34s
Continuous integration / build (push) Successful in 43s
Continuous integration / build-release (push) Successful in 1m12s
added swagget-ui
2026-02-15 18:04:11 +07:00

87 lines
2.8 KiB
Rust

use crate::model;
use crate::state;
use crate::utils;
use axum::extract::{Json, State};
use bcrypt::verify;
use chrono::{Duration, Utc};
use sqlx::Row;
use std::sync::Arc;
#[utoipa::path(
post,
path = "/api/login",
request_body = LoginRequest,
responses(
(status = 200, description = "Login successful", body = AuthResponse),
(status = 400, description = "Invalid credentials", body = AuthResponse)
)
)]
pub async fn login_handler(
State(state): State<Arc<state::AppState>>,
Json(payload): Json<model::LoginRequest>,
) -> Json<model::AuthResponse> {
// Get user from database
let user_result = sqlx::query("SELECT username, password_hash FROM users WHERE phone = ?")
.bind(&payload.phone)
.fetch_optional(&state.db_pool)
.await;
match user_result {
Ok(Some(row)) => {
let username: String = row.get("username");
let password_hash: String = row.get("password_hash");
// Verify password
match verify(&payload.password, &password_hash) {
Ok(true) => {
// Generate session token
let token = utils::generate_token();
let expires_at = Utc::now() + Duration::days(30);
// Store session
let _ = sqlx::query(
"INSERT INTO sessions (token, username, phone, expires_at) VALUES (?, ?, ?, ?)"
)
.bind(&token)
.bind(&username)
.bind(&payload.phone)
.bind(expires_at.naive_utc())
.execute(&state.db_pool)
.await;
Json(model::AuthResponse {
success: true,
message: "Login successful".to_string(),
username: Some(username),
token: Some(token),
})
}
Ok(false) => Json(model::AuthResponse {
success: false,
message: "Invalid password".to_string(),
username: None,
token: None,
}),
Err(_) => Json(model::AuthResponse {
success: false,
message: "Error verifying password".to_string(),
username: None,
token: None,
}),
}
}
Ok(None) => Json(model::AuthResponse {
success: false,
message: "Phone number not found".to_string(),
username: None,
token: None,
}),
Err(_) => Json(model::AuthResponse {
success: false,
message: "Login failed".to_string(),
username: None,
token: None,
}),
}
}