summaryrefslogtreecommitdiff
path: root/src/setup/routes
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/setup/routes
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/setup/routes')
-rw-r--r--src/setup/routes/mod.rs11
-rw-r--r--src/setup/routes/post.rs52
-rw-r--r--src/setup/routes/test.rs94
3 files changed, 0 insertions, 157 deletions
diff --git a/src/setup/routes/mod.rs b/src/setup/routes/mod.rs
deleted file mode 100644
index 977a790..0000000
--- a/src/setup/routes/mod.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-use axum::{Router, routing::post};
-
-use crate::app::App;
-
-mod post;
-#[cfg(test)]
-mod test;
-
-pub fn router() -> Router<App> {
- Router::new().route("/api/setup", post(post::handler))
-}
diff --git a/src/setup/routes/post.rs b/src/setup/routes/post.rs
deleted file mode 100644
index 0ff5d69..0000000
--- a/src/setup/routes/post.rs
+++ /dev/null
@@ -1,52 +0,0 @@
-use axum::{
- extract::{Json, State},
- http::StatusCode,
- response::{IntoResponse, Response},
-};
-
-use crate::{
- app::App,
- clock::RequestedAt,
- error::Internal,
- name::Name,
- setup::app,
- token::extract::IdentityCookie,
- user::{Password, User},
-};
-
-pub async fn handler(
- State(app): State<App>,
- RequestedAt(setup_at): RequestedAt,
- identity: IdentityCookie,
- Json(request): Json<Request>,
-) -> Result<(IdentityCookie, Json<User>), Error> {
- let (user, secret) = app
- .setup()
- .initial(&request.name, &request.password, &setup_at)
- .await
- .map_err(Error)?;
- let identity = identity.set(secret);
- Ok((identity, Json(user)))
-}
-
-#[derive(serde::Deserialize)]
-pub struct Request {
- pub name: Name,
- pub password: Password,
-}
-
-#[derive(Debug)]
-pub struct Error(pub app::Error);
-
-impl IntoResponse for Error {
- fn into_response(self) -> Response {
- let Self(error) = self;
- match error {
- app::Error::InvalidName(_) => {
- (StatusCode::BAD_REQUEST, error.to_string()).into_response()
- }
- app::Error::SetupCompleted => (StatusCode::CONFLICT, error.to_string()).into_response(),
- other => Internal::from(other).into_response(),
- }
- }
-}
diff --git a/src/setup/routes/test.rs b/src/setup/routes/test.rs
deleted file mode 100644
index e9f5cd6..0000000
--- a/src/setup/routes/test.rs
+++ /dev/null
@@ -1,94 +0,0 @@
-use axum::extract::{Json, State};
-
-use super::post;
-use crate::{setup::app, test::fixtures};
-
-#[tokio::test]
-async fn fresh_instance() {
- // Set up the environment
-
- let app = fixtures::scratch_app().await;
-
- // Call the endpoint
- let identity = fixtures::cookie::not_logged_in();
- let (name, password) = fixtures::user::propose();
- let request = post::Request {
- name: name.clone(),
- password: password.clone(),
- };
- let (identity, Json(response)) =
- post::handler(State(app.clone()), fixtures::now(), identity, Json(request))
- .await
- .expect("setup in a fresh app succeeds");
-
- // Verify the response
-
- assert_eq!(name, response.name);
-
- // Verify that the issued token is valid
-
- let secret = identity
- .secret()
- .expect("newly-issued identity has a token secret");
- let (_, login) = app
- .tokens()
- .validate(&secret, &fixtures::now())
- .await
- .expect("newly-issued identity cookie is valid");
- assert_eq!(response, login);
-
- // Verify that the given credentials can log in
-
- let (login, _) = app
- .tokens()
- .login(&name, &password, &fixtures::now())
- .await
- .expect("credentials given on signup are valid");
- assert_eq!(response, login);
-}
-
-#[tokio::test]
-async fn login_exists() {
- // Set up the environment
-
- let app = fixtures::scratch_app().await;
- fixtures::user::create(&app, &fixtures::now()).await;
-
- // Call the endpoint
- let identity = fixtures::cookie::not_logged_in();
- let (name, password) = fixtures::user::propose();
- let request = post::Request { name, password };
- let post::Error(error) =
- post::handler(State(app.clone()), fixtures::now(), identity, Json(request))
- .await
- .expect_err("setup in a populated app fails");
-
- // Verify the response
-
- assert!(matches!(error, app::Error::SetupCompleted));
-}
-
-#[tokio::test]
-async fn invalid_name() {
- // Set up the environment
-
- let app = fixtures::scratch_app().await;
-
- // Call the endpoint
-
- let name = fixtures::user::propose_invalid_name();
- let password = fixtures::user::propose_password();
- let identity = fixtures::cookie::not_logged_in();
- let request = post::Request {
- name: name.clone(),
- password: password.clone(),
- };
- let post::Error(error) =
- post::handler(State(app.clone()), fixtures::now(), identity, Json(request))
- .await
- .expect_err("setup with an invalid name fails");
-
- // Verify the response
-
- assert!(matches!(error, app::Error::InvalidName(error_name) if name == error_name));
-}