use actix_web::{http::StatusCode, post, web, HttpResponse, ResponseError, Scope}; use raise::yeet; use serde::Deserialize; use sqlx::MySqlPool; use thiserror::Error; use crate::services::db; #[derive(Debug, Clone, Deserialize)] struct LoginRequest { username: Box, password: Box, } #[derive(Debug, Clone, Error)] enum LoginFailure { #[error("No user found with the given username")] UserNotFound { username: Box }, #[error("The given password is incorrect")] IncorrectPassword { username: Box }, } impl ResponseError for LoginFailure { fn status_code(&self) -> actix_web::http::StatusCode { match self { Self::UserNotFound { .. } => StatusCode::NOT_FOUND, Self::IncorrectPassword { .. } => StatusCode::UNAUTHORIZED, } } } #[post("/login")] async fn login( body: web::Json, conn: web::Data, ) -> Result { let conn = conn.get_ref(); let user = db::get_user_by_username(conn, &body.username) .await .unwrap(); let Some(user) = user else { yeet!(LoginFailure::UserNotFound{ username: body.username.clone() }); }; let good_password = user.check_password(&body.password).unwrap(); let response = if good_password { HttpResponse::Ok().finish() } else { yeet!(LoginFailure::IncorrectPassword { username: body.username.clone() }); }; Ok(response) } pub fn service() -> Scope { web::scope("").service(login) }