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
#[cfg(feature = "scripting")]
16
pub mod script;
17
pub mod tag;
18
pub mod transaction;
19
pub mod validation;
20

            
21
3
pub async fn index(State(data): State<Arc<AppState>>, cookie_jar: CookieJar) -> impl IntoResponse {
22
3
    let _script = br#"
23
3
(module $commodity.wasm
24
3
  (type (;0;) (func (param i64)))
25
3
  (type (;1;) (func (param i32 i32)))
26
3
  (type (;2;) (func))
27
3
  (import "env" "set_frac" (func $set_frac (type 0)))
28
3
  (func $process (type 2)
29
3
    i64.const 15
30
3
    call $set_frac)
31
3
  (table (;0;) 1 1 funcref)
32
3
  (memory (;0;) 17)
33
3
  (global $__stack_pointer (mut i32) (i32.const 1048576))
34
3
  (global (;1;) i32 (i32.const 1048602))
35
3
  (global (;2;) i32 (i32.const 1048608))
36
3
  (export "memory" (memory 0))
37
3
  (export "process" (func $process))
38
3
  (export "__data_end" (global 1))
39
3
  (export "__heap_base" (global 2))
40
3
  (data $.rodata (i32.const 1048576) "!test value to check page!"))
41
3
"#;
42
3
    let is_logged_in = cookie_jar.get("access_token").is_some_and(|cookie| {
43
        crate::token::verify_jwt_token(&data.conf.access_token_public_key, cookie.value()).is_ok()
44
    });
45

            
46
    // User name will be empty for index page since it doesn't require auth
47
3
    let user_name = String::new();
48

            
49
3
    let template = IndexTemplate {
50
3
        fraction: data.frac,
51
3
        is_logged_in,
52
3
        user_name,
53
3
        scripting_enabled: cfg!(feature = "scripting"),
54
3
    };
55

            
56
3
    HtmlTemplate(template)
57
3
}
58

            
59
#[derive(Template)]
60
#[template(path = "pages/index.html")]
61
struct IndexTemplate {
62
    fraction: i64,
63
    is_logged_in: bool,
64
    user_name: String,
65
    scripting_enabled: bool,
66
}
67

            
68
1
pub async fn file_table(
69
1
    State(data): State<Arc<AppState>>,
70
1
) -> Result<impl IntoResponse, StatusCode> {
71
1
    let frac = State(&data).frac;
72
1
    let template = FileTableTemplate {
73
1
        files: list_s3(State(data)).await?,
74
1
        frac,
75
    };
76
1
    Ok(HtmlTemplate(template))
77
1
}
78

            
79
#[derive(Template)]
80
#[template(path = "components/file-table.html")]
81
struct FileTableTemplate {
82
    files: Vec<S3File>,
83
    frac: i64,
84
}
85

            
86
1
pub async fn register() -> impl IntoResponse {
87
1
    let template = RegisterTemplate {};
88
1
    HtmlTemplate(template)
89
1
}
90

            
91
#[derive(Template)]
92
#[template(path = "pages/register.html")]
93
struct RegisterTemplate;
94

            
95
1
pub async fn login() -> impl IntoResponse {
96
1
    let template = LoginTemplate {};
97
1
    HtmlTemplate(template)
98
1
}
99

            
100
#[derive(Template)]
101
#[template(path = "pages/login.html")]
102
struct LoginTemplate;
103

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

            
107
/// Allows us to convert Askama HTML templates into valid HTML for axum to serve in the response.
108
impl<T> IntoResponse for HtmlTemplate<T>
109
where
110
    T: Template,
111
{
112
9
    fn into_response(self) -> Response {
113
        // Attempt to render the template with askama
114
9
        match self.0.render() {
115
            // If we're able to successfully parse and aggregate the template, serve it
116
9
            Ok(html) => Html(html).into_response(),
117
            // If we're not, return an error or some bit of fallback HTML
118
            Err(err) => (
119
                StatusCode::INTERNAL_SERVER_ERROR,
120
                format!("Failed to render template. Error: {err}"),
121
            )
122
                .into_response(),
123
        }
124
9
    }
125
}