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 tag;
16
pub mod transaction;
17
pub mod validation;
18

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

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

            
47
6
    let template = IndexTemplate {
48
6
        fraction: data.frac,
49
6
        is_logged_in,
50
6
        user_name,
51
6
    };
52

            
53
6
    HtmlTemplate(template)
54
6
}
55

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

            
64
2
pub async fn file_table(
65
2
    State(data): State<Arc<AppState>>,
66
3
) -> Result<impl IntoResponse, StatusCode> {
67
2
    let frac = State(&data).frac;
68
2
    let template = FileTableTemplate {
69
2
        files: list_s3(State(data)).await?,
70
2
        frac,
71
    };
72
2
    Ok(HtmlTemplate(template))
73
2
}
74

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

            
82
3
pub async fn register() -> impl IntoResponse {
83
2
    let template = RegisterTemplate {};
84
2
    HtmlTemplate(template)
85
2
}
86

            
87
#[derive(Template)]
88
#[template(path = "pages/register.html")]
89
struct RegisterTemplate;
90

            
91
3
pub async fn login() -> impl IntoResponse {
92
2
    let template = LoginTemplate {};
93
2
    HtmlTemplate(template)
94
2
}
95

            
96
#[derive(Template)]
97
#[template(path = "pages/login.html")]
98
struct LoginTemplate;
99

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

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