use actix_web::web::{self, HttpResponse, Json}; use actix_web::{post, Responder}; use chrono::{Duration, Utc}; use jsonwebtoken::{encode, EncodingKey, Header}; use log::{debug, error}; use crate::{ data::{secret_key, Claims, CreateAccountRequest, LoginRequest, Token}, database::UserDao, }; #[post("/register")] async fn register( user: Json, user_dao: web::Data>, ) -> impl Responder { if !user.username.is_empty() && user.password.len() > 5 && user.password == user.confirmation { if user_dao.user_exists(&user.username) { HttpResponse::BadRequest() } else if let Some(_user) = user_dao.create_user(&user.username, &user.password) { HttpResponse::Ok() } else { HttpResponse::InternalServerError() } } else { HttpResponse::BadRequest() } } pub async fn login( creds: Json, user_dao: web::Data>, ) -> HttpResponse { debug!("Logging in: {}", creds.username); if let Some(user) = user_dao.get_user(&creds.username, &creds.password) { let claims = Claims { sub: user.id.to_string(), exp: (Utc::now() + Duration::days(5)).timestamp(), }; let token = encode( &Header::default(), &claims, &EncodingKey::from_secret(secret_key().as_bytes()), ) .unwrap(); HttpResponse::Ok().json(Token { token: &token }) } else { error!("User not found during login: '{}'", creds.username); HttpResponse::NotFound().finish() } } #[cfg(test)] mod tests { use super::*; use crate::database::testhelpers::{BodyReader, TestUserDao}; #[actix_rt::test] async fn test_login_reports_200_when_user_exists() { let dao = TestUserDao::new(); dao.create_user("user", "pass"); let j = Json(LoginRequest { username: "user".to_string(), password: "pass".to_string(), }); let response = login(j, web::Data::new(Box::new(dao))).await; assert_eq!(response.status(), 200); } #[actix_rt::test] async fn test_login_returns_token_on_success() { let dao = TestUserDao::new(); dao.create_user("user", "password"); let j = Json(LoginRequest { username: "user".to_string(), password: "password".to_string(), }); let response = login(j, web::Data::new(Box::new(dao))).await; assert_eq!(response.status(), 200); assert!(response.body().read_to_str().contains("\"token\"")); } #[actix_rt::test] async fn test_login_reports_400_when_user_does_not_exist() { let dao = TestUserDao::new(); dao.create_user("user", "password"); let j = Json(LoginRequest { username: "doesnotexist".to_string(), password: "password".to_string(), }); let response = login(j, web::Data::new(Box::new(dao))).await; assert_eq!(response.status(), 404); } }