Parent [>]
1use askama::Template;
2use axum::http::{StatusCode, header};
3use axum::response::{IntoResponse, Response};
4use thiserror::Error;
5
6#[derive(Debug, Error)]
7pub enum Error {
8    #[error(transparent)]
9    Io(#[from] std::io::Error),
10    #[error("repository not found: {0}")]
11    RepoNotFound(String),
12    #[error("not found: {0}")]
13    NotFound(String),
14    #[error("bad request: {0}")]
15    BadRequest(String),
16    #[error("corrupt object: {0}")]
17    GitCorrupt(String),
18}
19
20pub type Result<T> = std::result::Result<T, Error>;
21
22#[derive(Template)]
23#[template(path = "error.html")]
24struct ErrorTemplate {
25    status: u16,
26    kind: &'static str,
27    message: String,
28    base_url: String,
29}
30
31impl IntoResponse for Error {
32    fn into_response(self) -> Response {
33        let (status, kind) = match &self {
34            Error::RepoNotFound(_) | Error::NotFound(_) => (StatusCode::NOT_FOUND, "Not Found"),
35            Error::BadRequest(_) => (StatusCode::BAD_REQUEST, "Bad Request"),
36            Error::Io(_) | Error::GitCorrupt(_) => {
37                (StatusCode::INTERNAL_SERVER_ERROR, "Internal Server Error")
38            }
39        };
40
41        let tpl = ErrorTemplate {
42            status: status.as_u16(),
43            kind,
44            message: self.to_string(),
45            base_url: crate::base_url().to_string(),
46        };
47
48        match tpl.render() {
49            Ok(html) => ([(header::CONTENT_TYPE, "text/html; charset=utf-8")], html).into_response(),
50            Err(_) => (status, self.to_string()).into_response(),
51        }
52    }
53}