1
use std::sync::Arc;
2

            
3
use crate::AppState;
4

            
5
use crate::files::{S3File, list_s3};
6
use askama::Template;
7
use axum::{
8
    extract::State,
9
    http::StatusCode,
10
    response::{Html, IntoResponse, Response},
11
};
12
use axum_extra::extract::CookieJar;
13
pub mod account;
14
pub mod commodity;
15
pub mod report;
16
pub mod script;
17
pub mod tag;
18
pub mod template;
19
pub mod transaction;
20
pub mod validation;
21

            
22
3
pub async fn index(cookie_jar: CookieJar) -> impl IntoResponse {
23
3
    let is_logged_in = match cookie_jar.get("access_token") {
24
        // A directory outage renders the logged-out page rather than failing:
25
        // this only decides which navigation the index shows.
26
        Some(cookie) => crate::auth_keys::verify(cookie.value(), crate::token::TokenType::Access)
27
            .await
28
            .is_ok_and(|details| details.is_some()),
29
3
        None => false,
30
    };
31

            
32
3
    let template = IndexTemplate {
33
3
        is_logged_in,
34
3
        scripting_enabled: true,
35
3
    };
36

            
37
3
    HtmlTemplate(template)
38
3
}
39

            
40
#[derive(Template)]
41
#[template(path = "pages/index.html")]
42
struct IndexTemplate {
43
    is_logged_in: bool,
44
    scripting_enabled: bool,
45
}
46

            
47
1
pub async fn file_table(
48
1
    State(data): State<Arc<AppState>>,
49
1
) -> Result<impl IntoResponse, StatusCode> {
50
1
    let frac = State(&data).frac;
51
1
    let template = FileTableTemplate {
52
1
        files: list_s3(State(data)).await?,
53
1
        frac,
54
    };
55
1
    Ok(HtmlTemplate(template))
56
1
}
57

            
58
#[derive(Template)]
59
#[template(path = "components/file-table.html")]
60
struct FileTableTemplate {
61
    files: Vec<S3File>,
62
    frac: i64,
63
}
64

            
65
1
pub async fn register() -> impl IntoResponse {
66
1
    let template = RegisterTemplate {};
67
1
    HtmlTemplate(template)
68
1
}
69

            
70
#[derive(Template)]
71
#[template(path = "pages/register.html")]
72
struct RegisterTemplate;
73

            
74
1
pub async fn login() -> impl IntoResponse {
75
1
    let template = LoginTemplate {};
76
1
    HtmlTemplate(template)
77
1
}
78

            
79
#[derive(Template)]
80
#[template(path = "pages/login.html")]
81
struct LoginTemplate;
82

            
83
/// A wrapper type that we'll use to encapsulate HTML parsed by askama into valid HTML for axum to serve.
84
struct HtmlTemplate<T>(T);
85

            
86
/// Allows us to convert Askama HTML templates into valid HTML for axum to serve in the response.
87
impl<T> IntoResponse for HtmlTemplate<T>
88
where
89
    T: Template,
90
{
91
12
    fn into_response(self) -> Response {
92
        // Attempt to render the template with askama
93
12
        match self.0.render() {
94
            // If we're able to successfully parse and aggregate the template, serve it
95
12
            Ok(html) => Html(html).into_response(),
96
            // If we're not, return an error or some bit of fallback HTML
97
            Err(err) => (
98
                StatusCode::INTERNAL_SERVER_ERROR,
99
                format!("Failed to render template. Error: {err}"),
100
            )
101
                .into_response(),
102
        }
103
12
    }
104
}