use std::fmt; use axum::{ http::{HeaderMap, StatusCode}, routing::{get, post}, Json, Router, }; use crate::{ core::Core, handlers::{check_password, get_user, healthcheck, AuthRequest}, }; pub fn routes(core: Core) -> Router { Router::new() .route( "/api/v1/health", get({ let core = core.clone(); move || healthcheck(core) }), ) .route( "/api/v1/auth", post({ let core = core.clone(); move |req: Json| check_password(core, req) }), ) .route( // By default, just get the self user. "/api/v1/user", get({ let core = core.clone(); move |headers: HeaderMap| get_user(core, headers) }) ) } #[cfg(test)] mod test { use std::path::PathBuf; use axum::http::StatusCode; use axum_test::TestServer; use cool_asserts::assert_matches; use result_extended::ResultExt; use super::*; use crate::{ asset_db::FsAssets, core::Core, database::{Database, DbConn, SessionId, UserId}, handlers::UserProfile, }; fn setup_without_admin() -> (Core, TestServer) { let memory_db: Option = None; let conn = DbConn::new(memory_db); let core = Core::new(FsAssets::new(PathBuf::from("/home/savanni/Pictures")), conn); let app = routes(core.clone()); let server = TestServer::new(app).unwrap(); (core, server) } async fn setup_admin_enabled() -> (Core, TestServer) { let memory_db: Option = None; let conn = DbConn::new(memory_db); conn.save_user(Some(UserId::from("admin")), "admin", "aoeu", true, true) .await .unwrap(); let core = Core::new(FsAssets::new(PathBuf::from("/home/savanni/Pictures")), conn); let app = routes(core.clone()); let server = TestServer::new(app).unwrap(); (core, server) } #[tokio::test] async fn it_returns_a_healthcheck() { let (core, server) = setup_without_admin(); let response = server.get("/api/v1/health").await; response.assert_status_ok(); let b: crate::handlers::HealthCheck = response.json(); assert_eq!(b, crate::handlers::HealthCheck { ok: false }); assert_matches!( core.save_user(Some(UserId::from("admin")), "admin", "aoeu", true, true) .await, ResultExt::Ok(_) ); let response = server.get("/api/v1/health").await; response.assert_status_ok(); let b: crate::handlers::HealthCheck = response.json(); assert_eq!(b, crate::handlers::HealthCheck { ok: true }); } #[tokio::test] async fn it_authenticates_a_user() { let (_core, server) = setup_admin_enabled().await; let response = server .post("/api/v1/auth") .json(&AuthRequest { username: "admin".to_owned(), password: "wrong".to_owned(), }) .await; response.assert_status(StatusCode::UNAUTHORIZED); let response = server .post("/api/v1/auth") .json(&AuthRequest { username: "unknown".to_owned(), password: "wrong".to_owned(), }) .await; response.assert_status(StatusCode::UNAUTHORIZED); let response = server .post("/api/v1/auth") .json(&AuthRequest { username: "admin".to_owned(), password: "aoeu".to_owned(), }) .await; response.assert_status_ok(); let session_id: Option = response.json(); assert!(session_id.is_some()); } #[tokio::test] async fn it_returns_user_profile() { let (_core, server) = setup_admin_enabled().await; let response = server.get("/api/v1/user").await; response.assert_status(StatusCode::UNAUTHORIZED); let response = server .post("/api/v1/auth") .json(&AuthRequest { username: "admin".to_owned(), password: "aoeu".to_owned(), }) .await; response.assert_status_ok(); let session_id: Option = response.json(); let session_id = session_id.unwrap(); let response = server .get("/api/v1/user") .add_header("Authorization", format!("Bearer {}", session_id)) .await; response.assert_status_ok(); let profile: Option = response.json(); let profile = profile.unwrap(); assert_eq!(profile.userid, UserId::from("admin")); assert_eq!(profile.username, "admin"); } #[tokio::test] async fn an_admin_can_create_a_user() { unimplemented!(); } }