what2watch/src/lib.rs
2024-04-19 14:32:11 -07:00

141 lines
4.4 KiB
Rust

use axum::{
middleware,
routing::{get, post, IntoMakeService},
};
use axum_login::AuthManagerLayerBuilder;
use sqlx::SqlitePool;
#[macro_use]
extern crate justerror;
/// Some public interfaces for interacting with the database outside of the web
/// app
pub use db::get_db_pool;
pub mod conf;
pub mod imdb_utils;
pub mod import_utils;
pub mod misc_util;
pub use conf::*;
pub use signup::Invitation;
pub use stars::*;
pub use users::User;
pub use watches::{ShowKind, Watch, WatchQuest};
pub type WWRouter = axum::Router<SqlitePool>;
pub type WatchDate = chrono::DateTime<chrono::Utc>;
// everything else is private to the crate
mod auth;
mod db;
mod generic_handlers;
mod login;
mod search;
mod signup;
mod stars;
mod templates;
mod users;
mod watches;
// things we want in the crate namespace
use auth::AuthSession;
use optional_optional_user::OptionalOptionalUser;
use templates::*;
use watches::templates::*;
/// Returns the router to be used as a service or test object, you do you.
pub async fn app(db_pool: sqlx::SqlitePool) -> IntoMakeService<axum::Router> {
// don't bother bringing handlers into the whole crate namespace
use auth::*;
use generic_handlers::{handle_slash, handle_slash_redir};
use login::{get_login, get_logout, post_login, post_logout};
use search::get_search_watch;
use signup::handlers::{get_create_user, get_signup_success, post_create_user};
use tower_http::services::ServeDir;
use watches::handlers::{
edit_watch_quest, get_add_new_watch, get_watch, get_watch_status, get_watches,
post_add_new_watch, post_add_watch_quest,
};
let conf = crate::conf::Config::get();
tracing::info!("Using config: {conf:#?}");
let auth_layer = {
let session_layer = session_layer(db_pool.clone()).await;
let store = AuthStore::new(db_pool.clone());
AuthManagerLayerBuilder::new(store, session_layer).build()
};
let assets_dir = std::env::current_dir().unwrap().join("assets");
let assets_svc = ServeDir::new(assets_dir.as_path());
axum::Router::new()
.route("/", get(handle_slash).post(handle_slash))
.nest_service("/assets", assets_svc)
.route("/signup", post(post_create_user))
.route("/signup/:invitation", get(get_create_user))
.route("/signup_success/:user", get(get_signup_success))
.route("/login", get(get_login).post(post_login))
.route("/logout", get(get_logout).post(post_logout))
.route("/watches", get(get_watches))
.route("/watch", get(get_watch))
.route("/watch/:watch", get(get_watch))
.route("/watch/status/:watch", get(get_watch_status))
.route("/quest/edit", post(edit_watch_quest))
.route("/title-search", get(get_search_watch))
.route("/add", get(get_add_new_watch).post(post_add_new_watch))
.route(
"/add/watch",
get(get_search_watch).post(post_add_watch_quest),
)
.fallback(handle_slash_redir)
.layer(middleware::from_fn_with_state(
db_pool.clone(),
users::handle_update_last_seen,
))
.layer(auth_layer)
.with_state(db_pool)
.into_make_service()
}
#[cfg(test)]
pub mod test_utils;
//-************************************************************************
// tests for the proc macro for optional user
//-************************************************************************
#[cfg(test)]
mod test {
use super::{signup::templates::SignupSuccessPage, MainPage, OptionalOptionalUser, User};
#[test]
fn main_page_has_optional_user() {
assert!(MainPage::default().has_optional_user());
assert!(MainPage::default().has_user());
}
#[test]
fn signup_success_has_no_optional_user() {
assert!(!SignupSuccessPage::default().has_optional_user());
}
#[test]
fn user_is_not_optional() {
#[derive(Default, OptionalOptionalUser)]
struct TestThing {
user: User,
}
assert!(!TestThing::default().has_optional_user());
assert!(TestThing::default().has_mandatory_user());
assert!(TestThing::default().has_user());
}
#[test]
fn user_is_not_user() {
#[derive(Default, OptionalOptionalUser)]
struct TestThing {
user: Option<bool>,
}
assert!(!TestThing::default().has_optional_user());
assert!(!TestThing::default().has_user());
}
}