Skip to content

Commit 8a8a135

Browse files
committed
templates: Support inner errors
1 parent 89c4aee commit 8a8a135

File tree

4 files changed

+49
-12
lines changed

4 files changed

+49
-12
lines changed

src/routes/index.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use askama_web::WebTemplate;
33
use axum::extract::State;
44

55
use crate::extractors::user::User;
6-
use crate::state::{AppState, AppStateContext, error::AppStateError};
6+
use crate::state::{AppState, AppStateContext, error::*};
77

88
use std::collections::HashMap;
99

src/state/error.rs

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use askama::Template;
22
use askama_web::WebTemplate;
33
use axum::http::StatusCode;
44
use axum::response::{IntoResponse, Response};
5+
use snafu::ErrorCompat;
56
use snafu::prelude::*;
67

78
use super::free_space::FreeSpaceError;
@@ -15,30 +16,43 @@ pub enum AppStateError {
1516
API { source: hightorrent_api::ApiError },
1617
#[snafu(display("Failed to get free space information"))]
1718
FreeSpace { source: FreeSpaceError },
19+
#[snafu(display("An other error occurred"))]
20+
Other {
21+
source: Box<dyn snafu::Error + Send + Sync + 'static>,
22+
},
23+
}
24+
25+
impl AppStateError {
26+
pub fn inner_errors(&self) -> Vec<Box<dyn std::error::Error + '_>> {
27+
let mut inner_errors = vec![];
28+
for error in self.iter_chain().skip(1) {
29+
inner_errors.push(Box::new(error).into());
30+
}
31+
inner_errors
32+
}
1833
}
1934

2035
/// Global error page generated from an [AppStateError].
21-
#[derive(Clone, Debug, Template, WebTemplate)]
36+
#[derive(Debug, Template, WebTemplate)]
2237
#[template(path = "error.html")]
2338
pub struct AppStateErrorContext {
2439
state: AppStateErrorContextInner,
2540
}
2641

2742
/// Helper struct so we can reuse base.html
2843
/// with all it's `state.foo` expressions.
29-
#[derive(Clone, Debug)]
44+
#[derive(Debug)]
3045
pub struct AppStateErrorContextInner {
31-
// TODO: typed errors
32-
// errors: Vec<AppStateError>,
33-
errors: Vec<String>,
46+
// TODO: askama doesn't handle recursion well, so we convert
47+
// all errors to strings. Maybe related to:
48+
// https://github.com/askama-rs/askama/issues/393
49+
errors: Vec<AppStateError>,
3450
}
3551

3652
impl From<AppStateError> for AppStateErrorContext {
3753
fn from(e: AppStateError) -> Self {
3854
Self {
39-
state: AppStateErrorContextInner {
40-
errors: vec![e.to_string()],
41-
},
55+
state: AppStateErrorContextInner { errors: vec![e] },
4256
}
4357
}
4458
}
@@ -49,3 +63,19 @@ impl IntoResponse for AppStateError {
4963
(StatusCode::INTERNAL_SERVER_ERROR, error_context).into_response()
5064
}
5165
}
66+
67+
#[cfg(test)]
68+
mod tests {
69+
use super::*;
70+
71+
#[test]
72+
fn can_extract_from_any_error() {
73+
let res: Result<_, AppStateError> =
74+
std::fs::read("/tmp/qsjlkdjsqlkdsqfsqhsjklfhalkjfkjh.toml")
75+
.boxed()
76+
.context(OtherSnafu);
77+
78+
assert!(res.is_err());
79+
assert_eq!(&res.unwrap_err().to_string(), "An other error occurred");
80+
}
81+
}

src/state/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ pub struct AppState {
3131
pub struct AppStateContext {
3232
// TODO: proper categories
3333
pub categories: Vec<String>,
34-
pub errors: Vec<String>,
34+
pub errors: Vec<AppStateError>,
35+
// pub errors: Vec<String>,
3536
pub free_space: FreeSpace,
3637
}
3738

templates/base.html

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
{#{% import "menus/macro.html" as menus %}#}
21
<!DOCTYPE html>
32
<html>
43
<head>
@@ -17,7 +16,14 @@
1716
<div class="container">
1817
{% for error in state.errors %}
1918
<div class="notification is-danger">
20-
<h2 style="font-weight: bold; text-align: center;">{{ error }}</h2>
19+
<details>
20+
<summary>{{ error }}</summary>
21+
<ul class="ml-5">
22+
{% for inner_error in error.inner_errors() %}
23+
<li>→ {{ inner_error }}</li>
24+
{% endfor %}
25+
</ul>
26+
</details>
2127
</div>
2228
{% endfor %}
2329
</div>

0 commit comments

Comments
 (0)