Skip to content

Commit a44e28e

Browse files
committed
Remove app state
It's not needed anymore since we're most likely going to go with some sort of black-box end-to-end testing.
1 parent 35339e7 commit a44e28e

11 files changed

Lines changed: 105 additions & 139 deletions

File tree

backend/api.rs

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use std::error::Error as _;
55
use axum::{
66
extract::{
77
rejection::{JsonRejection, QueryRejection},
8-
Request, State,
8+
Request,
99
},
1010
http::StatusCode,
1111
response::IntoResponse,
@@ -17,8 +17,6 @@ use strum_macros::IntoStaticStr;
1717
use thiserror::Error;
1818
use tower::ServiceExt;
1919

20-
use crate::AppState;
21-
2220
mod captcha;
2321
mod routes;
2422
mod validation;
@@ -192,17 +190,9 @@ struct Query<T>(pub T);
192190
type Response<T> = std::result::Result<(StatusCode, Json<T>), Error>;
193191

194192
/// Routes a request to an API endpoint.
195-
pub(super) async fn handle(
196-
State(state): State<AppState>,
197-
request: Request,
198-
) -> axum::response::Response {
193+
pub(super) async fn handle(request: Request) -> axum::response::Response {
199194
// Calling the router needs a mutable reference to it (even though it shouldn't), so the router
200195
// must either have restricted access via a mutex or be cloned on each request. The former would
201196
// allow only one request at a time, so the latter is faster.
202-
ROUTER
203-
.clone()
204-
.with_state(state)
205-
.oneshot(request)
206-
.await
207-
.into_response()
197+
ROUTER.clone().oneshot(request).await.into_response()
208198
}

backend/api/routes.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use axum::{
88
};
99
use tower_cookies::CookieManagerLayer;
1010

11-
use crate::{api, AppState};
11+
use crate::api;
1212

1313
mod v1 {
1414
//! The routes for version 1 of the HTTP API.
@@ -20,7 +20,7 @@ mod v1 {
2020
}
2121

2222
/// The API router.
23-
pub(super) static ROUTER: LazyLock<Router<AppState>> = LazyLock::new(|| {
23+
pub(super) static ROUTER: LazyLock<Router> = LazyLock::new(|| {
2424
Router::new()
2525
.route(
2626
"/api/v1/email-verification",

backend/api/routes/v1/email_verification.rs

Lines changed: 26 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! The set of email verification requests for new users.
22
3-
use axum::{extract::State, http::StatusCode};
3+
use axum::http::StatusCode;
44
use axum_macros::debug_handler;
55
use lettre::message::Mailbox;
66
use serde::{Deserialize, Serialize};
@@ -16,7 +16,7 @@ use crate::{
1616
db::{self, TxResult},
1717
email::{EmailTakenMessage, MessageTemplate, SendMessage, VerificationMessage},
1818
id::Token,
19-
AppState, WEBSITE_ORIGIN,
19+
WEBSITE_ORIGIN,
2020
};
2121

2222
pub(crate) mod code;
@@ -47,25 +47,21 @@ pub(crate) enum GetQuery {
4747
///
4848
/// See [`crate::api::Error`].
4949
#[debug_handler]
50-
pub(crate) async fn get(
51-
State(state): State<AppState>,
52-
Query(query): Query<GetQuery>,
53-
) -> Response<GetResponse> {
50+
pub(crate) async fn get(Query(query): Query<GetQuery>) -> Response<GetResponse> {
5451
let email = match query {
5552
GetQuery::Token { token } => {
5653
let token_hash = hash_without_salt(&token);
5754

58-
let Some(unverified_email) =
59-
db::transaction!(&state.db_pool, async |tx| -> TxResult<_, api::Error> {
60-
Ok(sqlx::query!(
61-
"SELECT email FROM unverified_emails
62-
WHERE token_hash = $1 AND user_id IS NULL",
63-
token_hash.as_ref(),
64-
)
65-
.fetch_optional(tx.as_mut())
66-
.await?)
67-
})
68-
.await?
55+
let Some(unverified_email) = db::transaction!(async |tx| -> TxResult<_, api::Error> {
56+
Ok(sqlx::query!(
57+
"SELECT email FROM unverified_emails
58+
WHERE token_hash = $1 AND user_id IS NULL",
59+
token_hash.as_ref(),
60+
)
61+
.fetch_optional(tx.as_mut())
62+
.await?)
63+
})
64+
.await?
6965
else {
7066
return Err(api::Error::ResourceNotFound);
7167
};
@@ -74,19 +70,17 @@ pub(crate) async fn get(
7470
}
7571

7672
GetQuery::EmailAndCode { email, code } => {
77-
let Some(unverified_email) =
78-
db::transaction!(&state.db_pool, async |tx| -> TxResult<_, api::Error> {
79-
Ok(sqlx::query!(
80-
r#"SELECT email, code_hash as "code_hash!" FROM unverified_emails
81-
WHERE user_id IS NULL AND email = $1 AND code_hash IS NOT NULL"#,
82-
email.as_str(),
83-
)
84-
.fetch_optional(tx.as_mut())
85-
.await?)
86-
})
87-
.await?
88-
.filter(|unverified_email| verify_hash(&code, &unverified_email.code_hash))
89-
else {
73+
let Some(unverified_email) = db::transaction!(async |tx| -> TxResult<_, api::Error> {
74+
Ok(sqlx::query!(
75+
r#"SELECT email, code_hash as "code_hash!" FROM unverified_emails
76+
WHERE user_id IS NULL AND email = $1 AND code_hash IS NOT NULL"#,
77+
email.as_str(),
78+
)
79+
.fetch_optional(tx.as_mut())
80+
.await?)
81+
})
82+
.await?
83+
.filter(|unverified_email| verify_hash(&code, &unverified_email.code_hash)) else {
9084
return Err(api::Error::ResourceNotFound);
9185
};
9286

@@ -128,16 +122,13 @@ pub(crate) struct PostRequest {
128122
///
129123
/// See [`crate::api::Error`].
130124
#[debug_handler]
131-
pub(crate) async fn post(
132-
State(state): State<AppState>,
133-
Json(body): Json<PostRequest>,
134-
) -> Response<PostResponse> {
125+
pub(crate) async fn post(Json(body): Json<PostRequest>) -> Response<PostResponse> {
135126
// We don't want bots creating accounts or spamming people with verification emails.
136127
if !captcha::verify(&body.captcha_token).await? {
137128
return Err(api::Error::CaptchaFailed);
138129
}
139130

140-
db::transaction!(&state.db_pool, async |tx| -> TxResult<_, api::Error> {
131+
db::transaction!(async |tx| -> TxResult<_, api::Error> {
141132
let existing_user = sqlx::query!(
142133
"SELECT name FROM users
143134
WHERE email = $1",

backend/api/routes/v1/email_verification/code.rs

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! The verification code of a new user's email verification request.
22
3-
use axum::{extract::State, http::StatusCode};
3+
use axum::http::StatusCode;
44
use axum_macros::debug_handler;
55
use serde::{Deserialize, Serialize};
66

@@ -9,7 +9,6 @@ use crate::{
99
crypto::{generate_short_code, hash_with_salt, hash_without_salt},
1010
db::{self, TxResult},
1111
id::Token,
12-
AppState,
1312
};
1413

1514
/// A `POST` request query for this API route.
@@ -26,29 +25,25 @@ pub(crate) struct PostQuery {
2625
///
2726
/// See [`crate::api::Error`].
2827
#[debug_handler]
29-
pub(crate) async fn post(
30-
State(state): State<AppState>,
31-
Query(query): Query<PostQuery>,
32-
) -> Response<PostResponse> {
28+
pub(crate) async fn post(Query(query): Query<PostQuery>) -> Response<PostResponse> {
3329
let token_hash = hash_without_salt(&query.token);
3430

3531
let code = generate_short_code();
3632
let code_hash = hash_with_salt(&code);
3733

38-
let Some(unverified_email) =
39-
db::transaction!(&state.db_pool, async |tx| -> TxResult<_, api::Error> {
40-
Ok(sqlx::query!(
41-
"UPDATE unverified_emails
42-
SET code_hash = $1
43-
WHERE token_hash = $2 AND user_id IS NULL
44-
RETURNING email",
45-
code_hash,
46-
token_hash.as_ref(),
47-
)
48-
.fetch_optional(tx.as_mut())
49-
.await?)
50-
})
51-
.await?
34+
let Some(unverified_email) = db::transaction!(async |tx| -> TxResult<_, api::Error> {
35+
Ok(sqlx::query!(
36+
"UPDATE unverified_emails
37+
SET code_hash = $1
38+
WHERE token_hash = $2 AND user_id IS NULL
39+
RETURNING email",
40+
code_hash,
41+
token_hash.as_ref(),
42+
)
43+
.fetch_optional(tx.as_mut())
44+
.await?)
45+
})
46+
.await?
5247
else {
5348
return Err(api::Error::ResourceNotFound);
5449
};

backend/api/routes/v1/password_reset.rs

Lines changed: 16 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! The set of email verification requests for new users.
22
3-
use axum::{extract::State, http::StatusCode};
3+
use axum::http::StatusCode;
44
use axum_macros::debug_handler;
55
use lettre::message::Mailbox;
66
use serde::{Deserialize, Serialize};
@@ -16,7 +16,7 @@ use crate::{
1616
db::{self, TxResult},
1717
email::{MessageTemplate, PasswordResetFailedMessage, PasswordResetMessage, SendMessage},
1818
id::Token,
19-
AppState, WEBSITE_ORIGIN,
19+
WEBSITE_ORIGIN,
2020
};
2121

2222
pub(crate) mod password;
@@ -35,24 +35,20 @@ pub(crate) struct GetQuery {
3535
///
3636
/// See [`crate::api::Error`].
3737
#[debug_handler]
38-
pub(crate) async fn get(
39-
State(state): State<AppState>,
40-
Query(query): Query<GetQuery>,
41-
) -> Response<GetResponse> {
38+
pub(crate) async fn get(Query(query): Query<GetQuery>) -> Response<GetResponse> {
4239
let token_hash = hash_without_salt(&query.token);
4340

44-
let Some(password_reset) =
45-
db::transaction!(&state.db_pool, async |tx| -> TxResult<_, api::Error> {
46-
Ok(sqlx::query!(
47-
"SELECT users.email
48-
FROM password_resets JOIN users ON users.id = password_resets.user_id
49-
WHERE password_resets.token_hash = $1",
50-
token_hash.as_ref(),
51-
)
52-
.fetch_optional(tx.as_mut())
53-
.await?)
54-
})
55-
.await?
41+
let Some(password_reset) = db::transaction!(async |tx| -> TxResult<_, api::Error> {
42+
Ok(sqlx::query!(
43+
"SELECT users.email
44+
FROM password_resets JOIN users ON users.id = password_resets.user_id
45+
WHERE password_resets.token_hash = $1",
46+
token_hash.as_ref(),
47+
)
48+
.fetch_optional(tx.as_mut())
49+
.await?)
50+
})
51+
.await?
5652
else {
5753
return Err(api::Error::ResourceNotFound);
5854
};
@@ -91,16 +87,13 @@ pub(crate) struct PostRequest {
9187
///
9288
/// See [`crate::api::Error`].
9389
#[debug_handler]
94-
pub(crate) async fn post(
95-
State(state): State<AppState>,
96-
Json(body): Json<PostRequest>,
97-
) -> Response<PostResponse> {
90+
pub(crate) async fn post(Json(body): Json<PostRequest>) -> Response<PostResponse> {
9891
// We don't want bots spamming people with password reset emails.
9992
if !captcha::verify(&body.captcha_token).await? {
10093
return Err(api::Error::CaptchaFailed);
10194
}
10295

103-
db::transaction!(&state.db_pool, async |tx| -> TxResult<_, api::Error> {
96+
db::transaction!(async |tx| -> TxResult<_, api::Error> {
10497
let Some(user) = sqlx::query!(
10598
"SELECT id, name FROM users
10699
WHERE email = $1",

backend/api/routes/v1/password_reset/password.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! The new password for a user's password reset request.
22
3-
use axum::{extract::State, http::StatusCode};
3+
use axum::http::StatusCode;
44
use axum_macros::debug_handler;
55
use serde::{Deserialize, Serialize};
66

@@ -9,7 +9,6 @@ use crate::{
99
crypto::{hash_with_salt, hash_without_salt},
1010
db::{self, TxError, TxResult},
1111
id::Token,
12-
AppState,
1312
};
1413

1514
/// A `POST` request query for this API route.
@@ -35,15 +34,14 @@ pub(crate) struct PostRequest {
3534
/// See [`crate::api::Error`].
3635
#[debug_handler]
3736
pub(crate) async fn post(
38-
State(state): State<AppState>,
3937
Query(query): Query<PostQuery>,
4038
Json(body): Json<PostRequest>,
4139
) -> Response<PostResponse> {
4240
let token_hash = hash_without_salt(&query.token);
4341

4442
let password_hash = hash_with_salt(&body.password);
4543

46-
db::transaction!(&state.db_pool, async |tx| -> TxResult<_, api::Error> {
44+
db::transaction!(async |tx| -> TxResult<_, api::Error> {
4745
let Some(password_reset) = sqlx::query!(
4846
"DELETE FROM password_resets
4947
WHERE token_hash = $1

backend/api/routes/v1/sessions.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
use std::sync::LazyLock;
44

5-
use axum::{extract::State, http::StatusCode};
5+
use axum::http::StatusCode;
66
use axum_macros::debug_handler;
77
use serde::{Deserialize, Serialize};
88
use sqlx::Acquire;
@@ -20,7 +20,7 @@ use crate::{
2020
crypto::{hash_without_salt, verify_hash},
2121
db::{self, TxResult},
2222
id::Token,
23-
AppState, WEBSITE_ORIGIN,
23+
WEBSITE_ORIGIN,
2424
};
2525

2626
/// The domain for the website.
@@ -47,11 +47,10 @@ pub(crate) struct PostRequest {
4747
/// See [`crate::api::Error`].
4848
#[debug_handler]
4949
pub(crate) async fn post(
50-
State(state): State<AppState>,
5150
cookies: Cookies,
5251
Json(body): Json<PostRequest>,
5352
) -> Response<PostResponse> {
54-
let token = db::transaction!(&state.db_pool, async |tx| -> TxResult<_, api::Error> {
53+
let token = db::transaction!(async |tx| -> TxResult<_, api::Error> {
5554
let Some(user) = sqlx::query!(
5655
"SELECT id, password_hash FROM users
5756
WHERE email = $1",

backend/api/routes/v1/users.rs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! The set of all users.
22
3-
use axum::{extract::State, http::StatusCode};
3+
use axum::http::StatusCode;
44
use axum_macros::debug_handler;
55
use serde::{Deserialize, Serialize};
66
use sqlx::Acquire;
@@ -14,7 +14,6 @@ use crate::{
1414
crypto::{hash_with_salt, verify_hash},
1515
db::{self, TxError, TxResult},
1616
id::NewUserId,
17-
AppState,
1817
};
1918

2019
/// A `POST` request body for this API route.
@@ -40,15 +39,12 @@ pub(crate) struct PostRequest {
4039
///
4140
/// See [`crate::api::Error`].
4241
#[debug_handler]
43-
pub(crate) async fn post(
44-
State(state): State<AppState>,
45-
Json(body): Json<PostRequest>,
46-
) -> Response<PostResponse> {
42+
pub(crate) async fn post(Json(body): Json<PostRequest>) -> Response<PostResponse> {
4743
let mut user_id = NewUserId::generate();
4844

4945
let password_hash = hash_with_salt(&body.password);
5046

51-
db::transaction!(&state.db_pool, async |tx| -> TxResult<_, api::Error> {
47+
db::transaction!(async |tx| -> TxResult<_, api::Error> {
5248
let Some(unverified_email) = sqlx::query!(
5349
"DELETE FROM unverified_emails
5450
WHERE user_id IS NULL AND email = $1

0 commit comments

Comments
 (0)