samjeston / openhub Public
Sam Jeston Working vertical 9aa3c45 · History
62 lines· 2.0 KB ·Rust
Raw
1use axum::http::StatusCode;
2use axum::response::{IntoResponse, Redirect, Response};
3
4/// Errors returned by page handlers. The context middleware turns these into
5/// full HTML error pages.
6#[derive(Debug)]
7pub enum AppError {
8 NotFound,
9 Forbidden(String),
10 BadRequest(String),
11 /// Redirects to the sign-in page, returning to the given path afterwards.
12 LoginRequired(String),
13 Internal(anyhow::Error),
14}
15
16impl<E: Into<anyhow::Error>> From<E> for AppError {
17 fn from(e: E) -> Self {
18 AppError::Internal(e.into())
19 }
20}
21
22/// Marker attached to error responses so the middleware can render them.
23#[derive(Debug, Clone)]
24pub struct ErrorPage {
25 pub status: StatusCode,
26 pub title: &'static str,
27 pub message: String,
28}
29
30impl IntoResponse for AppError {
31 fn into_response(self) -> Response {
32 let (status, title, message) = match self {
33 AppError::LoginRequired(next) => {
34 let target = format!("/login?next={}", super::fmt::urlencode(&next));
35 return Redirect::to(&target).into_response();
36 }
37 AppError::NotFound => (
38 StatusCode::NOT_FOUND,
39 "Page not found",
40 "The page you are looking for does not exist, or you do not have access to it."
41 .to_string(),
42 ),
43 AppError::Forbidden(msg) => (StatusCode::FORBIDDEN, "Access denied", msg),
44 AppError::BadRequest(msg) => (StatusCode::BAD_REQUEST, "Bad request", msg),
45 AppError::Internal(err) => {
46 tracing::error!("internal error: {err:#}");
47 (
48 StatusCode::INTERNAL_SERVER_ERROR,
49 "Something went wrong",
50 "An unexpected error occurred. Please try again.".to_string(),
51 )
52 }
53 };
54 let mut resp = (status, format!("{title}: {message}")).into_response();
55 resp.extensions_mut().insert(ErrorPage {
56 status,
57 title,
58 message,
59 });
60 resp
61 }
62}