aboutsummaryrefslogtreecommitdiff
path: root/src/templates.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/templates.rs')
-rw-r--r--src/templates.rs164
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> {