diff options
Diffstat (limited to 'src/templates.rs')
-rw-r--r-- | src/templates.rs | 164 |
1 files changed, 106 insertions, 58 deletions
diff --git a/src/templates.rs b/src/templates.rs index 1f86717..c9a750b 100644 --- a/src/templates.rs +++ b/src/templates.rs @@ -1,9 +1,5 @@ use serde::Serialize; -use serde_json::json; -use serde_json::value::Value; -use std::collections::HashMap; -use tera::Tera; -use tera::{Error, Result}; +use std::fs; use crate::queries; @@ -16,71 +12,123 @@ pub enum Header { Statistics, } -pub fn get() -> Tera { - let mut tera = match Tera::new("templates/**/*") { - Ok(t) => t, - Err(e) => { - log::error!("Parsing error(s): {}", e); - ::std::process::exit(1); - } +pub fn get() -> Result<minijinja::Environment<'static>, String> { + let mut env = minijinja::Environment::new(); + for path in read_files_recursive("templates") { + let path = path + .to_str() + .ok_or("Error getting string of path: {path:?}")? + .to_string(); + let content = fs::read_to_string(&path) + .map_err(|_| "Error reading template {path}")?; + let path_without_prefix = path + .strip_prefix("templates/") + .ok_or("Error removing prefix from template path")? + .to_string(); + env.add_template_owned(path_without_prefix, content) + .map_err(|_| "Error adding template {path} to environment")?; + } + + env.add_function("payments_params", payments_params); + env.add_function("pluralize", pluralize); + env.add_function("now", now); + + env.add_filter("numeric", numeric); + env.add_filter("euros", euros); + env.add_filter("round", round); + env.add_filter("with_param", with_param); + env.add_filter("filter", filter); + + Ok(env) +} + +fn read_files_recursive( + path: impl AsRef<std::path::Path>, +) -> Vec<std::path::PathBuf> { + let Ok(entries) = fs::read_dir(path) else { + return vec![]; }; - tera.register_function("payments_params", payments_params); - tera.register_filter("numeric", numeric); - tera.register_filter("euros", euros); - tera + entries + .flatten() + .flat_map(|entry| { + let Ok(meta) = entry.metadata() else { + return vec![]; + }; + if meta.is_dir() { + return read_files_recursive(entry.path()); + } + if meta.is_file() { + return vec![entry.path()]; + } + vec![] + }) + .collect() } -fn payments_params(args: &HashMap<String, Value>) -> Result<Value> { - let q = json!({ - "page": args.get("page"), - "name": args.get("name"), - "cost": args.get("cost"), - "frequency": args.get("frequency"), - "highlight": args.get("highlight"), - "user": args.get("user"), - "category": args.get("category"), - "start_date": args.get("start_date"), - "end_date": args.get("end_date"), - }); - - match serde_json::from_value(q) { - Ok(q) => Ok(json!(queries::payments_url(q))), - Err(msg) => Err(Error::msg(msg)), +fn payments_params(value: minijinja::Value) -> String { + let str = value.to_string().replace("none", "null"); + match serde_json::from_str(&str) { + Ok(q) => queries::payments_url(q), + Err(err) => { + log::error!("Error parsing payments params {}: {:?}", str, err); + "".to_string() + } } } -fn euros(value: &Value, _: &HashMap<String, Value>) -> Result<Value> { - match value { - Value::Number(n) => { - if let Some(n) = n.as_i64() { - let str = rgrouped(n.abs().to_string(), 3).join(" "); - let sign = if n < 0 { "-" } else { "" }; - Ok(json!(format!("{}{} €", sign, str))) - } else if let Some(n) = n.as_f64() { - Ok(json!(format!("{} €", n))) - } else { - Err(Error::msg("Error parsing number")) - } - } - _ => Err(Error::msg(format!("{:?} should be a number", value))), +fn now(format: &str) -> String { + let date = chrono::Local::now(); + format!("{}", date.format(format)) +} + +fn euros(n: i64) -> String { + let str = rgrouped(n.abs().to_string(), 3).join(" "); + let sign = if n < 0 { "-" } else { "" }; + format!("{}{} €", sign, str) +} + +fn numeric(n: i64) -> String { + let str = rgrouped(n.abs().to_string(), 3).join(" "); + let sign = if n < 0 { "-" } else { "" }; + format!("{}{}", sign, str) +} + +fn pluralize(n: i32, s: String) -> String { + if n > 0 { + format!("{s}s") + } else { + s + } +} + +fn round(n: f32) -> i32 { + n.round() as i32 +} + +fn with_param(url: String, key: String, value: String) -> String { + if url.contains("?") { + format!("{url}&{key}={value}") + } else { + format!("{url}?{key}={value}") } } -fn numeric(value: &Value, _: &HashMap<String, Value>) -> Result<Value> { - match value { - Value::Number(n) => { - if let Some(n) = n.as_i64() { - let str = rgrouped(n.abs().to_string(), 3).join(" "); - let sign = if n < 0 { "-" } else { "" }; - Ok(json!(format!("{}{}", sign, str))) - } else if let Some(n) = n.as_f64() { - Ok(json!(format!("{}", n))) - } else { - Err(Error::msg("Error parsing number")) +fn filter( + xs: Vec<minijinja::Value>, + key: &str, + value: String, +) -> Vec<minijinja::Value> { + let mut res = vec![]; + for x in xs { + if let Ok(v) = x.get_attr(key) { + if let Some(v) = v.as_str() { + if v == value { + res.push(x); + } } } - _ => Err(Error::msg(format!("{:?} should be a number", value))), } + res } fn rgrouped(str: String, n: usize) -> Vec<String> { |