use crate::database::establish_connection; use crate::diesel; use crate::error::AppError; use crate::json_serialization::login::Login; use crate::models::user::rss_user::User; use crate::schema::users; use crate::{auth::jwt::JwtToken, schema::users::username}; use actix_web::{web, HttpResponse}; use diesel::prelude::*; pub async fn login(credentials: web::Json) -> Result { let username_cred: String = credentials.username.clone(); let password: String = credentials.password.clone(); let mut connection = establish_connection(); let users: Vec = users::table .filter(username.eq(username_cred.as_str())) .load::(&mut connection)?; if users.is_empty() { return Ok(HttpResponse::NotFound().finish()); } else if users.len() > 1 { log::error!( "multiple user have the usernam: {}", credentials.username.clone() ); return Ok(HttpResponse::Conflict().finish()); } let user: &User = &users[0]; match user.clone().verify(password)? { true => { log::info!("verified password successfully for user {}", user.id); let token: String = JwtToken::encode(user.id, user.token_version); Ok(HttpResponse::Ok() .insert_header(("token", token)) .insert_header(("user_id", user.id)) .finish()) } false => Ok(HttpResponse::Unauthorized().finish()), } } #[cfg(test)] mod tests { use actix_web::http::StatusCode; use actix_web::{test, web, App}; use super::login; use crate::database::establish_connection; use crate::test_helpers::{delete_user, insert_user, unique_suffix}; #[actix_web::test] async fn login_succeeds_with_correct_credentials() { let mut connection = establish_connection(); let user = insert_user(&mut connection, "correct-password"); let app = test::init_service(App::new().route("/login", web::post().to(login))).await; let req = test::TestRequest::post() .uri("/login") .set_json(serde_json::json!({ "username": user.username, "password": "correct-password" })) .to_request(); let resp = test::call_service(&app, req).await; assert_eq!(StatusCode::OK, resp.status()); assert!(resp.headers().contains_key("token")); delete_user(&mut connection, user.id); } #[actix_web::test] async fn login_fails_with_wrong_password() { let mut connection = establish_connection(); let user = insert_user(&mut connection, "correct-password"); let app = test::init_service(App::new().route("/login", web::post().to(login))).await; let req = test::TestRequest::post() .uri("/login") .set_json(serde_json::json!({ "username": user.username, "password": "wrong-password" })) .to_request(); let resp = test::call_service(&app, req).await; assert_eq!(StatusCode::UNAUTHORIZED, resp.status()); delete_user(&mut connection, user.id); } #[actix_web::test] async fn login_fails_for_unknown_user() { let app = test::init_service(App::new().route("/login", web::post().to(login))).await; let req = test::TestRequest::post() .uri("/login") .set_json(serde_json::json!({ "username": format!("does-not-exist-{}", unique_suffix()), "password": "whatever" })) .to_request(); let resp = test::call_service(&app, req).await; assert_eq!(StatusCode::NOT_FOUND, resp.status()); } }