From 5ed96f8e8b9d9f19ee249f5c73a5a21ef6bca09f Mon Sep 17 00:00:00 2001 From: Owen Jacobson Date: Tue, 17 Jun 2025 02:03:28 -0400 Subject: Reorganize and consolidate HTTP routes. HTTP routes are now defined in a single, unified module, pulling them out of the topical modules they were formerly part of. This is intended to improve the navigability of the codebase. Previously, finding the handler corresponding to a specific endpoint required prior familiarity, though in practice you could usually guess from topic area. Now, all routes are defined in `crate::routes`. Other than changing visibility, I've avoided making changes to the handlers at the ends of those routes. --- src/routes.rs | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 src/routes.rs (limited to 'src/routes.rs') diff --git a/src/routes.rs b/src/routes.rs new file mode 100644 index 0000000..5bb5f91 --- /dev/null +++ b/src/routes.rs @@ -0,0 +1,83 @@ +use axum::{ + Router, middleware, + response::Redirect, + routing::{delete, get, post}, +}; + +use crate::{app::App, boot, channel, event, expire, invite, message, setup, ui, user}; + +pub fn routes(app: &App) -> Router { + // UI routes that can be accessed before the administrator completes setup. + let ui_bootstrap = Router::new() + .route("/{*path}", get(ui::routes::path::get::handler)) + .route("/setup", get(ui::routes::setup::get::handler)); + + // UI routes that require the administrator to complete setup first. + let ui_setup_required = Router::new() + .route("/", get(ui::routes::get::handler)) + .route("/ch/{channel}", get(ui::routes::ch::channel::get::handler)) + .route( + "/invite/{invite}", + get(ui::routes::invite::invite::get::handler), + ) + .route("/login", get(ui::routes::login::get::handler)) + .route("/me", get(ui::routes::me::get::handler)) + .route_layer(crate::setup::Required(app.clone()).with_fallback(Redirect::to("/setup"))); + + // API routes that can run before the administrator completes setup. + let api_bootstrap = Router::new().route("/api/setup", post(setup::routes::post::handler)); + + // API routes that require the administrator to complete setup first. + let api_setup_required = Router::new() + .route("/api/auth/login", post(user::routes::login::post::handler)) + .route( + "/api/auth/logout", + post(user::routes::logout::post::handler), + ) + .route("/api/boot", get(boot::routes::get::handler)) + .route("/api/channels", post(channel::routes::post::handler)) + .route( + "/api/channels/{channel}", + post(channel::routes::channel::post::handler), + ) + .route( + "/api/channels/{channel}", + delete(channel::routes::channel::delete::handler), + ) + .route("/api/events", get(event::routes::get::handler)) + .route("/api/invite", post(invite::routes::post::handler)) + .route( + "/api/invite/{invite}", + get(invite::routes::invite::get::handler), + ) + .route( + "/api/invite/{invite}", + post(invite::routes::invite::post::handler), + ) + .route( + "/api/messages/{message}", + delete(message::routes::message::delete::handler), + ) + .route("/api/password", post(user::routes::password::post::handler)) + // Run expiry whenever someone accesses the API. This was previously a blanket middleware + // affecting the whole service, but loading the client makes a several requests before the + // client can completely load, each of which was triggering expiry. There is absolutely no + // upside to re-checking expiry tens of times back-to-back like that; the API is accessed + // more regularly and with less of a traffic rush. + // + // This should, probably, be moved to a background job at some point. + .route_layer(middleware::from_fn_with_state( + app.clone(), + expire::middleware, + )) + .route_layer(setup::Required(app.clone())); + + [ + ui_bootstrap, + ui_setup_required, + api_bootstrap, + api_setup_required, + ] + .into_iter() + .fold(Router::default(), Router::merge) +} -- cgit v1.2.3