summaryrefslogtreecommitdiff
path: root/src/login
diff options
context:
space:
mode:
authorOwen Jacobson <owen@grimoire.ca>2024-09-18 12:16:43 -0400
committerOwen Jacobson <owen@grimoire.ca>2024-09-18 12:18:58 -0400
commit9fb4d3e561786f01352cbd14894d994ea537b5ec (patch)
tree959ddcf4592c6140b71be38149051c56a788bcfe /src/login
parent2b4cf5c62ff82fa408a4f82bde0b561ff3b15497 (diff)
Return 404s when resources are not found.
This is implemented by making the return values, in most cases, idiosyncratic ad-hoc types that then convert to the approprate error response. This also should make endpoints more testable, since the return values can now be inspected to check their properties without having to process or parse an HTTP response.
Diffstat (limited to 'src/login')
-rw-r--r--src/login/routes.rs41
1 files changed, 24 insertions, 17 deletions
diff --git a/src/login/routes.rs b/src/login/routes.rs
index 3c58b10..1ed61ce 100644
--- a/src/login/routes.rs
+++ b/src/login/routes.rs
@@ -8,7 +8,7 @@ use axum::{
use crate::{app::App, clock::RequestedAt, error::InternalError};
-use super::{app::LoginError, extract::IdentityToken};
+use super::{app, extract::IdentityToken};
pub fn router() -> Router<App> {
Router::new()
@@ -27,29 +27,36 @@ async fn on_login(
RequestedAt(now): RequestedAt,
identity: IdentityToken,
Form(form): Form<LoginRequest>,
-) -> Result<impl IntoResponse, InternalError> {
- match app.logins().login(&form.name, &form.password, now).await {
- Ok(token) => {
- let identity = identity.set(&token);
- Ok(LoginResponse::Successful(identity))
- }
- Err(LoginError::Rejected) => Ok(LoginResponse::Rejected),
- Err(other) => Err(other.into()),
- }
+) -> Result<LoginSuccess, LoginError> {
+ let token = app
+ .logins()
+ .login(&form.name, &form.password, now)
+ .await
+ .map_err(LoginError)?;
+ let identity = identity.set(&token);
+ Ok(LoginSuccess(identity))
}
-enum LoginResponse {
- Rejected,
- Successful(IdentityToken),
+struct LoginSuccess(IdentityToken);
+
+impl IntoResponse for LoginSuccess {
+ fn into_response(self) -> Response {
+ let Self(identity) = self;
+ (identity, Redirect::to("/")).into_response()
+ }
}
-impl IntoResponse for LoginResponse {
+struct LoginError(app::LoginError);
+
+impl IntoResponse for LoginError {
fn into_response(self) -> Response {
- match self {
- Self::Successful(identity) => (identity, Redirect::to("/")).into_response(),
- Self::Rejected => {
+ let Self(error) = self;
+ match error {
+ app::LoginError::Rejected => {
(StatusCode::UNAUTHORIZED, "invalid name or password").into_response()
}
+ app::LoginError::DatabaseError(error) => InternalError::from(error).into_response(),
+ app::LoginError::PasswordHashError(error) => InternalError::from(error).into_response(),
}
}
}