// src/auth/handlers/login.rs use bcrypt::verify; use tonic::{Request, Response, Status}; use crate::db::PgPool; use crate::auth::{models::AuthError, logic::jwt}; // Fixed import path use common::proto::multieko2::auth::{LoginRequest, LoginResponse}; pub async fn login( pool: &PgPool, request: LoginRequest, ) -> Result, Status> { let user = sqlx::query!( r#" SELECT id, username, password_hash, role FROM users WHERE username = $1 OR email = $1 "#, request.identifier ) .fetch_optional(pool) .await .map_err(|e| Status::internal(e.to_string()))? .ok_or_else(|| Status::unauthenticated("Invalid credentials"))?; // Handle the optional password_hash let password_hash = user.password_hash .ok_or_else(|| Status::internal("User account has no password set"))?; // Verify the password if !verify(&request.password, &password_hash) .map_err(|e| Status::internal(e.to_string()))? { return Err(Status::unauthenticated("Invalid credentials")); } let token = jwt::generate_token(user.id, &user.role, &user.username) .map_err(|e| Status::internal(e.to_string()))?; Ok(Response::new(LoginResponse { access_token: token, token_type: "Bearer".to_string(), expires_in: 86400, // 24 hours user_id: user.id.to_string(), role: user.role, username: user.username, })) }