Skip to main content

web/
route.rs

1use std::sync::Arc;
2
3use axum::{
4    Router, middleware,
5    routing::{get, post},
6};
7
8#[cfg(feature = "scripting")]
9use crate::pages::script;
10#[cfg(feature = "scripting")]
11use crate::pages::template;
12use crate::{
13    AppState,
14    files::download_file,
15    handler::{
16        get_home_link, get_logout_link, get_me_handler, get_version, login_form_handler,
17        login_user_handler, logout_handler, refresh_access_token_handler, register_user_handler,
18    },
19    jwt_auth::{admin, auth},
20    pages::{account, commodity, file_table, report, tag},
21    redirect_middleware::redirect_on_auth_error,
22};
23
24pub fn create_pages_router(app_state: Arc<AppState>) -> Router<Arc<AppState>> {
25    Router::new()
26        .route(
27            "/commodity/create",
28            get(crate::pages::commodity::create::submit::commodity_create_page),
29        )
30        .route(
31            "/commodity/list",
32            get(crate::pages::commodity::list::commodity_list_page),
33        )
34        .route_layer(middleware::from_fn_with_state(app_state.clone(), auth))
35        .route_layer(middleware::from_fn(redirect_on_auth_error))
36        .with_state(app_state.clone())
37}
38
39pub fn create_accounts_router(app_state: Arc<AppState>) -> Router<Arc<AppState>> {
40    Router::new()
41        .route(
42            "/account/create",
43            get(crate::pages::account::create::submit::account_create_page),
44        )
45        .route(
46            "/account/list",
47            get(crate::pages::account::list::account_list_page),
48        )
49        .route(
50            "/account/manage",
51            get(crate::pages::account::manage::account_manage_page),
52        )
53        .route(
54            "/account/ssh-key",
55            get(crate::pages::account::ssh_key::ssh_key_page),
56        )
57        .route_layer(middleware::from_fn_with_state(app_state.clone(), auth))
58        .route_layer(middleware::from_fn(redirect_on_auth_error))
59        .with_state(app_state.clone())
60}
61
62pub fn create_transactions_router(app_state: Arc<AppState>) -> Router<Arc<AppState>> {
63    Router::new()
64        .route(
65            "/transaction/create",
66            get(crate::pages::transaction::create::submit::transaction_create_page),
67        )
68        .route(
69            "/transaction/list",
70            get(crate::pages::transaction::list::transaction_list_page),
71        )
72        .route(
73            "/transaction/edit/{id}",
74            get(crate::pages::transaction::edit::submit::transaction_edit_page),
75        )
76        .route_layer(middleware::from_fn_with_state(app_state.clone(), auth))
77        .route_layer(middleware::from_fn(redirect_on_auth_error))
78        .with_state(app_state.clone())
79}
80
81pub fn create_tags_router(app_state: Arc<AppState>) -> Router<Arc<AppState>> {
82    Router::new()
83        .route(
84            "/tag/create",
85            get(crate::pages::tag::create::tag_create_page),
86        )
87        .route("/tag/list", get(crate::pages::tag::list::tag_list_page))
88        .route(
89            "/tag/edit/{id}",
90            get(crate::pages::tag::edit::tag_edit_page),
91        )
92        .route_layer(middleware::from_fn_with_state(app_state.clone(), auth))
93        .route_layer(middleware::from_fn(redirect_on_auth_error))
94        .with_state(app_state.clone())
95}
96
97#[cfg(feature = "scripting")]
98pub fn create_scripts_router(app_state: Arc<AppState>) -> Router<Arc<AppState>> {
99    Router::new()
100        .route("/script/create", get(script::edit::script_create_page))
101        .route("/script/list", get(script::list::script_list_page))
102        .route("/script/edit/{id}", get(script::edit::script_edit_page))
103        .route(
104            "/template/create",
105            get(template::edit::template_create_page),
106        )
107        .route("/template/list", get(template::list::template_list_page))
108        .route(
109            "/template/edit/{id}",
110            get(template::edit::template_edit_page),
111        )
112        .route_layer(middleware::from_fn_with_state(app_state.clone(), auth))
113        .route_layer(middleware::from_fn(redirect_on_auth_error))
114        .with_state(app_state.clone())
115}
116
117pub fn create_reports_router(app_state: Arc<AppState>) -> Router<Arc<AppState>> {
118    Router::new()
119        .route("/report/balance", get(report::balance::balance_report_page))
120        .route(
121            "/report/activity",
122            get(report::activity::activity_report_page),
123        )
124        .route(
125            "/report/category-breakdown",
126            get(report::category_breakdown::category_breakdown_report_page),
127        )
128        .route_layer(middleware::from_fn_with_state(app_state.clone(), auth))
129        .route_layer(middleware::from_fn(redirect_on_auth_error))
130        .with_state(app_state.clone())
131}
132
133pub fn create_api_router(app_state: Arc<AppState>) -> Router<Arc<AppState>> {
134    let public_router = Router::new()
135        .route("/auth/login", post(login_form_handler))
136        .route("/auth/login/json", post(login_user_handler))
137        .route("/version", get(get_version));
138
139    let auth_router = Router::new()
140        .route("/auth/refresh", get(refresh_access_token_handler))
141        .route("/files/list", get(file_table))
142        .route("/files/download/{file_name}", get(download_file))
143        .route("/auth/logout", get(logout_handler))
144        .route("/users/me", get(get_me_handler))
145        .route("/htmx/logoutlink", get(get_logout_link))
146        .route_layer(middleware::from_fn_with_state(app_state.clone(), auth))
147        .with_state(app_state.clone());
148
149    let account_router = Router::new()
150        .route("/account/list", get(account::list::account_table))
151        .route("/account/info", get(account::list::account_info))
152        .route("/account/tree", get(account::manage::account_tree))
153        .route(
154            "/account/manage/view",
155            get(account::manage::account_manage_view),
156        )
157        .route(
158            "/account/manage/details",
159            get(account::manage::account_manage_details),
160        )
161        .route(
162            "/account/manage/tag",
163            post(account::manage::account_manage_set_tag),
164        )
165        .route(
166            "/account/manage/tag/submit",
167            post(account::manage::account_manage_set_tag_submit),
168        )
169        .route(
170            "/account/manage/tag/delete/{tag_id}",
171            post(account::manage::account_manage_delete_tag_submit),
172        )
173        .route("/account/search", post(account::search::search_accounts))
174        .route(
175            "/account/create/submit",
176            post(account::create::submit::create_account),
177        )
178        .route(
179            "/account/create/validate/name",
180            post(account::create::validate::validate_name),
181        )
182        .route("/account/rename", post(account::edit::rename_account))
183        .route(
184            "/account/{id}/tags/submit",
185            post(account::edit::account_tags_submit),
186        )
187        .route("/account/ssh-key/add", post(account::ssh_key::ssh_key_add))
188        .route(
189            "/account/ssh-key/remove",
190            post(account::ssh_key::ssh_key_remove),
191        )
192        .route_layer(middleware::from_fn_with_state(app_state.clone(), auth))
193        .with_state(app_state.clone());
194
195    let nav_router = Router::new()
196        .route("/nav/home", get(get_home_link))
197        .route_layer(middleware::from_fn_with_state(app_state.clone(), auth))
198        .with_state(app_state.clone());
199
200    let commodity_router = Router::new()
201        .route("/commodity/list", get(commodity::list::commodity_table))
202        .route(
203            "/commodity/search",
204            post(commodity::search::search_commodities),
205        )
206        .route(
207            "/commodity/create/submit",
208            post(commodity::create::submit::commodity_submit),
209        )
210        .route(
211            "/commodity/create/validate/symbol",
212            post(commodity::create::validate::validate_symbol),
213        )
214        .route(
215            "/commodity/create/validate/name",
216            post(commodity::create::validate::validate_name),
217        )
218        .route_layer(middleware::from_fn_with_state(app_state.clone(), auth))
219        .with_state(app_state.clone());
220
221    let transaction_router = Router::new()
222        .route(
223            "/transaction/list",
224            get(crate::pages::transaction::list::transaction_table),
225        )
226        .route(
227            "/transaction/split/create",
228            get(crate::pages::transaction::create::split::split_create_handler),
229        )
230        .route(
231            "/transaction/create/submit",
232            post(crate::pages::transaction::create::submit::transaction_submit),
233        )
234        .route(
235            "/transaction/create/validate/amount",
236            post(crate::pages::transaction::validate::validate_amount_html),
237        )
238        .route(
239            "/transaction/create/validate/from_account",
240            post(crate::pages::transaction::validate::validate_from_account_html),
241        )
242        .route(
243            "/transaction/create/validate/to_account",
244            post(crate::pages::transaction::validate::validate_to_account_html),
245        )
246        .route(
247            "/transaction/create/validate/note",
248            post(crate::pages::transaction::validate::validate_note_html),
249        )
250        .route(
251            "/transaction/edit/submit",
252            post(crate::pages::transaction::edit::submit::transaction_edit_submit),
253        )
254        .route(
255            "/transaction/edit/validate/amount",
256            post(crate::pages::transaction::validate::validate_amount_json),
257        )
258        .route(
259            "/transaction/edit/validate/from_account",
260            post(crate::pages::transaction::validate::validate_from_account_json),
261        )
262        .route(
263            "/transaction/edit/validate/to_account",
264            post(crate::pages::transaction::validate::validate_to_account_json),
265        )
266        .route(
267            "/transaction/edit/validate/note",
268            post(crate::pages::transaction::validate::validate_note_json),
269        )
270        .route(
271            "/transaction/delete/{id}",
272            post(crate::pages::transaction::delete::submit::transaction_delete_submit),
273        )
274        .route_layer(middleware::from_fn_with_state(app_state.clone(), auth))
275        .with_state(app_state.clone());
276
277    let tag_router = Router::new()
278        .route("/tag/list", get(tag::list::tag_table))
279        .route("/tag/create/submit", post(tag::create::create_tag))
280        .route(
281            "/transaction/{id}/tag/create/submit",
282            post(tag::create::create_transaction_tag),
283        )
284        .route(
285            "/split/{id}/tag/create/submit",
286            post(tag::create::create_split_tag),
287        )
288        .route(
289            "/account/{id}/tag/create/submit",
290            post(tag::create::create_account_tag),
291        )
292        .route("/tag/edit/submit", post(tag::edit::edit_tag))
293        .route("/tag/delete/{id}", post(tag::edit::delete_tag))
294        .route(
295            "/tags/transaction/names",
296            get(tag::autocomplete::transaction_tag_names),
297        )
298        .route(
299            "/tags/transaction/values",
300            get(tag::autocomplete::transaction_tag_values),
301        )
302        .route("/tags/split/names", get(tag::autocomplete::split_tag_names))
303        .route(
304            "/tags/split/values",
305            get(tag::autocomplete::split_tag_values),
306        )
307        .route(
308            "/tags/account/names",
309            get(tag::autocomplete::account_tag_names),
310        )
311        .route(
312            "/tags/account/values",
313            get(tag::autocomplete::account_tag_values),
314        )
315        .route_layer(middleware::from_fn_with_state(app_state.clone(), auth))
316        .with_state(app_state.clone());
317
318    #[cfg(feature = "scripting")]
319    let script_router = Router::new()
320        .route("/script/list", get(script::list::script_table))
321        .route("/script/create/submit", post(script::edit::create_script))
322        .route("/script/edit/submit", post(script::edit::edit_script))
323        .route(
324            "/script/bytecode/{id}",
325            post(script::edit::upload_script_bytecode),
326        )
327        .route("/script/delete/{id}", post(script::edit::delete_script))
328        .route(
329            "/account/{account_id}/script/run/{script_id}",
330            post(account::edit::run_account_script),
331        )
332        .route("/template/list", get(template::list::template_table))
333        .route(
334            "/template/create/submit",
335            post(template::edit::create_template),
336        )
337        .route("/template/test", post(template::edit::test_template))
338        .route("/template/edit/submit", post(template::edit::edit_template))
339        .route(
340            "/template/delete/{id}",
341            post(template::edit::delete_template),
342        )
343        .route_layer(middleware::from_fn_with_state(app_state.clone(), auth))
344        .with_state(app_state.clone());
345
346    let report_router = Router::new()
347        .route(
348            "/report/balance",
349            get(report::balance::balance_report_table),
350        )
351        .route(
352            "/report/balance/chart.svg",
353            get(report::balance::balance_report_chart_svg),
354        )
355        .route(
356            "/report/balance/chart.json",
357            get(report::balance::balance_report_chart_json),
358        )
359        .route(
360            "/report/activity",
361            get(report::activity::activity_report_table),
362        )
363        .route(
364            "/report/activity/chart.svg",
365            get(report::activity::activity_report_chart_svg),
366        )
367        .route(
368            "/report/activity/chart.json",
369            get(report::activity::activity_report_chart_json),
370        )
371        .route(
372            "/report/category-breakdown",
373            get(report::category_breakdown::category_breakdown_report_table),
374        )
375        .route(
376            "/report/category-breakdown/chart.svg",
377            get(report::category_breakdown::category_breakdown_report_chart_svg),
378        )
379        .route(
380            "/report/category-breakdown/chart.json",
381            get(report::category_breakdown::category_breakdown_report_chart_json),
382        )
383        .route_layer(middleware::from_fn_with_state(app_state.clone(), auth))
384        .with_state(app_state.clone());
385
386    let admin_router = Router::new()
387        .route("/auth/register", post(register_user_handler))
388        .route_layer(middleware::from_fn_with_state(app_state.clone(), admin))
389        .route_layer(middleware::from_fn_with_state(app_state, auth));
390
391    let router = Router::new()
392        .merge(public_router)
393        .merge(nav_router)
394        .merge(auth_router)
395        .merge(account_router)
396        .merge(commodity_router)
397        .merge(transaction_router)
398        .merge(tag_router)
399        .merge(report_router)
400        .merge(admin_router);
401
402    #[cfg(feature = "scripting")]
403    let router = router.merge(script_router);
404
405    router
406}