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