summaryrefslogtreecommitdiff
path: root/src/routes.rs
diff options
context:
space:
mode:
authorojacobson <ojacobson@noreply.codeberg.org>2025-06-21 04:22:52 +0200
committerojacobson <ojacobson@noreply.codeberg.org>2025-06-21 04:22:52 +0200
commitcd1dc0dab4b46bc5712070812192d5ce34071470 (patch)
treec94f5a42f7e734b81892c1289a1d2b566706ba7c /src/routes.rs
parentd84ba5cd09b713fac2f193d5c05af7415ea6742d (diff)
parent4e3d5ccac99b24934c972e088cd7eb02bb95df06 (diff)
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 one place; if you know the path, you can read down the list to find the handler. Handlers themselves live with the domain they are most appropriately "part of," generally (in this version, universally) in a `handlers` submodule. The handlers themselves have been flattened down; rather than representing a path and a method, they now represent a named operation (which is suspiciously similar to the path in most cases). This means that we no longer have constructs like `crate::ui::routes::ch::channel` - it's now `crate::ui::handlers::channel` instead. ## Disclaimer I Solemnly Swear I Didn't Change Any Handlers. ## Prior art I've inadvertently reinvented Django's `urls.py` convention, and I've opted to lean into that. Merges flatter-routes-reorg into main.
Diffstat (limited to 'src/routes.rs')
-rw-r--r--src/routes.rs62
1 files changed, 62 insertions, 0 deletions
diff --git a/src/routes.rs b/src/routes.rs
new file mode 100644
index 0000000..1e66582
--- /dev/null
+++ b/src/routes.rs
@@ -0,0 +1,62 @@
+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<App> {
+ // UI routes that can be accessed before the administrator completes setup.
+ let ui_bootstrap = Router::new()
+ .route("/{*path}", get(ui::handlers::asset))
+ .route("/setup", get(ui::handlers::setup));
+
+ // UI routes that require the administrator to complete setup first.
+ let ui_setup_required = Router::new()
+ .route("/", get(ui::handlers::index))
+ .route("/ch/{channel}", get(ui::handlers::channel))
+ .route("/invite/{invite}", get(ui::handlers::invite))
+ .route("/login", get(ui::handlers::login))
+ .route("/me", get(ui::handlers::me))
+ .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::handlers::setup));
+
+ // API routes that require the administrator to complete setup first.
+ let api_setup_required = Router::new()
+ .route("/api/auth/login", post(user::handlers::login))
+ .route("/api/auth/logout", post(user::handlers::logout))
+ .route("/api/boot", get(boot::handlers::boot))
+ .route("/api/channels", post(channel::handlers::create))
+ .route("/api/channels/{channel}", post(channel::handlers::send))
+ .route("/api/channels/{channel}", delete(channel::handlers::delete))
+ .route("/api/events", get(event::handlers::stream))
+ .route("/api/invite", post(invite::handlers::issue))
+ .route("/api/invite/{invite}", get(invite::handlers::get))
+ .route("/api/invite/{invite}", post(invite::handlers::accept))
+ .route("/api/messages/{message}", delete(message::handlers::delete))
+ .route("/api/password", post(user::handlers::change_password))
+ // 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)
+}