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

            
24
3
pub async fn index(State(data): State<Arc<AppState>>, cookie_jar: CookieJar) -> impl IntoResponse {
25
3
    let _script = br#"
26
3
(module $commodity.wasm
27
3
  (type (;0;) (func (param i64)))
28
3
  (type (;1;) (func (param i32 i32)))
29
3
  (type (;2;) (func))
30
3
  (import "env" "set_frac" (func $set_frac (type 0)))
31
3
  (func $process (type 2)
32
3
    i64.const 15
33
3
    call $set_frac)
34
3
  (table (;0;) 1 1 funcref)
35
3
  (memory (;0;) 17)
36
3
  (global $__stack_pointer (mut i32) (i32.const 1048576))
37
3
  (global (;1;) i32 (i32.const 1048602))
38
3
  (global (;2;) i32 (i32.const 1048608))
39
3
  (export "memory" (memory 0))
40
3
  (export "process" (func $process))
41
3
  (export "__data_end" (global 1))
42
3
  (export "__heap_base" (global 2))
43
3
  (data $.rodata (i32.const 1048576) "!test value to check page!"))
44
3
"#;
45
3
    let is_logged_in = match cookie_jar.get("access_token") {
46
        Some(cookie) => crate::auth_keys::verify(cookie.value(), crate::token::TokenType::Access)
47
            .await
48
            .is_some(),
49
3
        None => false,
50
    };
51

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

            
55
3
    let template = IndexTemplate {
56
3
        fraction: data.frac,
57
3
        is_logged_in,
58
3
        user_name,
59
3
        scripting_enabled: cfg!(feature = "scripting"),
60
3
    };
61

            
62
3
    HtmlTemplate(template)
63
3
}
64

            
65
#[derive(Template)]
66
#[template(path = "pages/index.html")]
67
struct IndexTemplate {
68
    fraction: i64,
69
    is_logged_in: bool,
70
    user_name: String,
71
    scripting_enabled: bool,
72
}
73

            
74
1
pub async fn file_table(
75
1
    State(data): State<Arc<AppState>>,
76
1
) -> Result<impl IntoResponse, StatusCode> {
77
1
    let frac = State(&data).frac;
78
1
    let template = FileTableTemplate {
79
1
        files: list_s3(State(data)).await?,
80
1
        frac,
81
    };
82
1
    Ok(HtmlTemplate(template))
83
1
}
84

            
85
#[derive(Template)]
86
#[template(path = "components/file-table.html")]
87
struct FileTableTemplate {
88
    files: Vec<S3File>,
89
    frac: i64,
90
}
91

            
92
1
pub async fn register() -> impl IntoResponse {
93
1
    let template = RegisterTemplate {};
94
1
    HtmlTemplate(template)
95
1
}
96

            
97
#[derive(Template)]
98
#[template(path = "pages/register.html")]
99
struct RegisterTemplate;
100

            
101
1
pub async fn login() -> impl IntoResponse {
102
1
    let template = LoginTemplate {};
103
1
    HtmlTemplate(template)
104
1
}
105

            
106
#[derive(Template)]
107
#[template(path = "pages/login.html")]
108
struct LoginTemplate;
109

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

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