diff options
author | Joris | 2025-01-26 17:58:57 +0100 |
---|---|---|
committer | Joris | 2025-01-26 17:58:57 +0100 |
commit | 24eeb54a6b7159964e8887ade7fa5173b50feb3a (patch) | |
tree | 91af6253df784445db9b084b02b38b37a83224e8 | |
parent | c5759f348e70cf54b4bfa4cd17e1fe1828ead30a (diff) |
Replace tera by minijinjamain
tera was doing the job all right, but minijinja has fewer dependencies.
35 files changed, 377 insertions, 605 deletions
@@ -187,16 +187,6 @@ dependencies = [ ] [[package]] -name = "bstr" -version = "1.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "531a9155a481e2ee699d4f98f43c0ca4ff8ee1bfd55c31e9e98fb29d2b176fe0" -dependencies = [ - "memchr", - "serde", -] - -[[package]] name = "budget" version = "0.1.0" dependencies = [ @@ -209,6 +199,7 @@ dependencies = [ "hyper", "hyper-util", "log", + "minijinja", "rand", "rand_core", "serde", @@ -217,7 +208,6 @@ dependencies = [ "sha2", "sqlx", "sqlx-core", - "tera", "tokio", "tokio-util", "url", @@ -271,28 +261,6 @@ dependencies = [ ] [[package]] -name = "chrono-tz" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93698b29de5e97ad0ae26447b344c482a7284c737d9ddc5f9e52b74a336671bb" -dependencies = [ - "chrono", - "chrono-tz-build", - "phf", -] - -[[package]] -name = "chrono-tz-build" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c088aee841df9c3041febbb73934cfc39708749bf96dc827e3359cd39ef11b1" -dependencies = [ - "parse-zoneinfo", - "phf", - "phf_codegen", -] - -[[package]] name = "cipher" version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -354,25 +322,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" [[package]] -name = "crossbeam-deque" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" -dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" -dependencies = [ - "crossbeam-utils", -] - -[[package]] name = "crossbeam-queue" version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -409,12 +358,6 @@ dependencies = [ ] [[package]] -name = "deunicode" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "339544cc9e2c4dc3fc7149fd630c5f22263a4fdf18a98afd0075784968b5cf00" - -[[package]] name = "digest" version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -651,30 +594,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] -name = "globset" -version = "0.4.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15f1ce686646e7f1e19bf7d5533fe443a45dbfb990e00629110797578b42fb19" -dependencies = [ - "aho-corasick", - "bstr", - "log", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "globwalk" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf760ebf69878d9fd8f110c89703d90ce35095324d1f1edcb595c63945ee757" -dependencies = [ - "bitflags", - "ignore", - "walkdir", -] - -[[package]] name = "h2" version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -799,15 +718,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] -name = "humansize" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cb51c9a029ddc91b07a787f1d86b53ccfa49b0e86688c946ebe8d3555685dd7" -dependencies = [ - "libm", -] - -[[package]] name = "humantime" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1016,22 +926,6 @@ dependencies = [ ] [[package]] -name = "ignore" -version = "0.4.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d89fd380afde86567dfba715db065673989d6253f42b88179abd3eae47bda4b" -dependencies = [ - "crossbeam-deque", - "globset", - "log", - "memchr", - "regex-automata", - "same-file", - "walkdir", - "winapi-util", -] - -[[package]] name = "indexmap" version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1149,6 +1043,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] +name = "memo-map" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d1115007560874e373613744c6fba374c17688327a71c1476d1a5954cc857b" + +[[package]] +name = "minijinja" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212b4cab3aad057bc6e611814472905546c533295723b9e26a31c7feb19a8e65" +dependencies = [ + "memo-map", + "self_cell", + "serde", +] + +[[package]] name = "miniz_oxide" version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1260,15 +1171,6 @@ dependencies = [ ] [[package]] -name = "parse-zoneinfo" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f2a05b18d44e2957b88f96ba460715e295bc1d7510468a2f3d3b44535d26c24" -dependencies = [ - "regex", -] - -[[package]] name = "pem-rfc7468" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1284,89 +1186,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] -name = "pest" -version = "2.7.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b7cafe60d6cf8e62e1b9b2ea516a089c008945bb5a275416789e7db0bc199dc" -dependencies = [ - "memchr", - "thiserror", - "ucd-trie", -] - -[[package]] -name = "pest_derive" -version = "2.7.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "816518421cfc6887a0d62bf441b6ffb4536fcc926395a69e1a85852d4363f57e" -dependencies = [ - "pest", - "pest_generator", -] - -[[package]] -name = "pest_generator" -version = "2.7.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d1396fd3a870fc7838768d171b4616d5c91f6cc25e377b673d714567d99377b" -dependencies = [ - "pest", - "pest_meta", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "pest_meta" -version = "2.7.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1e58089ea25d717bfd31fb534e4f3afcc2cc569c70de3e239778991ea3b7dea" -dependencies = [ - "once_cell", - "pest", - "sha2", -] - -[[package]] -name = "phf" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" -dependencies = [ - "phf_shared", -] - -[[package]] -name = "phf_codegen" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" -dependencies = [ - "phf_generator", - "phf_shared", -] - -[[package]] -name = "phf_generator" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" -dependencies = [ - "phf_shared", - "rand", -] - -[[package]] -name = "phf_shared" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" -dependencies = [ - "siphasher", -] - -[[package]] name = "pin-project-lite" version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1607,21 +1426,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] +name = "self_cell" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2fdfc24bc566f839a2da4c4295b82db7d25a24253867d5c64355abb5799bdbe" + +[[package]] name = "serde" version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1713,12 +1529,6 @@ dependencies = [ ] [[package]] -name = "siphasher" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" - -[[package]] name = "slab" version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1728,16 +1538,6 @@ dependencies = [ ] [[package]] -name = "slug" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "882a80f72ee45de3cc9a5afeb2da0331d58df69e4e7d8eeb5d3c7784ae67e724" -dependencies = [ - "deunicode", - "wasm-bindgen", -] - -[[package]] name = "smallvec" version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2029,28 +1829,6 @@ dependencies = [ ] [[package]] -name = "tera" -version = "1.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab9d851b45e865f178319da0abdbfe6acbc4328759ff18dafc3a41c16b4cd2ee" -dependencies = [ - "chrono", - "chrono-tz", - "globwalk", - "humansize", - "lazy_static", - "percent-encoding", - "pest", - "pest_derive", - "rand", - "regex", - "serde", - "serde_json", - "slug", - "unic-segment", -] - -[[package]] name = "thiserror" version = "2.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2199,62 +1977,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] -name = "ucd-trie" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" - -[[package]] -name = "unic-char-property" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" -dependencies = [ - "unic-char-range", -] - -[[package]] -name = "unic-char-range" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" - -[[package]] -name = "unic-common" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" - -[[package]] -name = "unic-segment" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4ed5d26be57f84f176157270c112ef57b86debac9cd21daaabbe56db0f88f23" -dependencies = [ - "unic-ucd-segment", -] - -[[package]] -name = "unic-ucd-segment" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2079c122a62205b421f499da10f3ee0f7697f012f55b675e002483c73ea34700" -dependencies = [ - "unic-char-property", - "unic-char-range", - "unic-ucd-version", -] - -[[package]] -name = "unic-ucd-version" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" -dependencies = [ - "unic-common", -] - -[[package]] name = "unicode-bidi" version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2329,16 +2051,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] -name = "walkdir" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" -dependencies = [ - "same-file", - "winapi-util", -] - -[[package]] name = "want" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2437,15 +2149,6 @@ dependencies = [ ] [[package]] -name = "winapi-util" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] name = "windows-core" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -14,6 +14,7 @@ http-body-util = "0.1" hyper = { version = "1.5", features = ["full"] } hyper-util = { version = "0.1", features = ["full"] } log = "0.4" +minijinja = { version = "2.6", features = ["loader"] } rand = { version = "0.8", features = ["getrandom"] } rand_core = "0.6" serde = { version = "1.0", features = ["derive"] } @@ -22,7 +23,6 @@ serde_urlencoded = "0.7" sha2 = "0.10" sqlx = { version = "0.8", features = ["runtime-tokio-rustls", "sqlite", "chrono"] } sqlx-core = "0.8" -tera = { version = "1.20", features = ["builtins"] } tokio = { version = "1", features = ["full"] } tokio-util = { version = "0.7", features = ["codec"] } url = "2.5" diff --git a/src/assets.rs b/src/assets.rs index 36fab55..fdfbfdd 100644 --- a/src/assets.rs +++ b/src/assets.rs @@ -1,8 +1,8 @@ use sha2::{Digest, Sha256}; use std::collections::HashMap; +use std::fmt::Write; use std::fs; use std::iter::FromIterator; -use std::fmt::Write; pub fn get() -> HashMap<String, String> { let paths = fs::read_dir("assets").unwrap().map(|e| { diff --git a/src/controller/balance.rs b/src/controller/balance.rs index c5d9d4a..efe5af6 100644 --- a/src/controller/balance.rs +++ b/src/controller/balance.rs @@ -2,7 +2,6 @@ use http_body_util::Full; use hyper::body::Bytes; use hyper::Response; use std::collections::HashMap; -use tera::Context; use crate::controller::utils; use crate::controller::wallet::Wallet; @@ -31,18 +30,16 @@ pub async fn get(wallet: &Wallet) -> Response<Full<Bytes>> { let exceeding_payers = payer::exceeding(&users, &user_incomes, &user_payments); - let mut context = Context::new(); - context.insert("header", &templates::Header::Balance); - context.insert("connected_user", &wallet.user); - context.insert( - "incomes_from", - &incomes_from.map(|d| d.format("%d/%m/%Y").to_string()), + let context = minijinja::context!( + header => templates::Header::Balance, + connected_user => wallet.user, + incomes_from => incomes_from.map(|d| d.format("%d/%m/%Y").to_string()), + total_income => total_income, + user_incomes => template_user_incomes, + total_payments => total_payments, + user_payments => template_user_payments, + exceeding_payers => exceeding_payers ); - context.insert("total_income", &total_income); - context.insert("user_incomes", &template_user_incomes); - context.insert("total_payments", &total_payments); - context.insert("user_payments", &template_user_payments); - context.insert("exceeding_payers", &exceeding_payers); utils::template(&wallet.assets, &wallet.templates, "balance.html", context) } diff --git a/src/controller/categories.rs b/src/controller/categories.rs index ff2d8e7..fbbd309 100644 --- a/src/controller/categories.rs +++ b/src/controller/categories.rs @@ -2,7 +2,6 @@ use http_body_util::Full; use hyper::body::Bytes; use hyper::Response; use std::collections::HashMap; -use tera::Context; use crate::controller::utils; use crate::controller::wallet::Wallet; @@ -17,11 +16,12 @@ pub async fn table( ) -> Response<Full<Bytes>> { let categories = db::categories::list(&wallet.pool).await; - let mut context = Context::new(); - context.insert("header", &templates::Header::Categories); - context.insert("connected_user", &wallet.user); - context.insert("categories", &categories); - context.insert("highlight", &query.highlight); + let context = minijinja::context!( + header => templates::Header::Categories, + connected_user => wallet.user, + categories => categories, + highlight => query.highlight + ); utils::template( &wallet.assets, @@ -40,11 +40,12 @@ async fn create_form_feedback( form: HashMap<String, String>, error: Option<String>, ) -> Response<Full<Bytes>> { - let mut context = Context::new(); - context.insert("header", &templates::Header::Categories); - context.insert("connected_user", &wallet.user.clone()); - context.insert("form", &form); - context.insert("error", &error); + let context = minijinja::context!( + header => &templates::Header::Categories, + connected_user => &wallet.user.clone(), + form => &form, + error => &error + ); utils::template( &wallet.assets, @@ -89,14 +90,15 @@ async fn update_form_feedback( let is_category_used = db::payments::is_category_used(&wallet.pool, id).await; - let mut context = Context::new(); - context.insert("header", &templates::Header::Categories); - context.insert("connected_user", &wallet.user); - context.insert("id", &id); - context.insert("category", &category); - context.insert("is_category_used", &is_category_used); - context.insert("form", &form); - context.insert("error", &error); + let context = minijinja::context!( + header => templates::Header::Categories, + connected_user => wallet.user, + id => id, + category => category, + is_category_used => is_category_used, + form => form, + error => error + ); utils::template( &wallet.assets, diff --git a/src/controller/error.rs b/src/controller/error.rs index 0f6dcc1..fb1375c 100644 --- a/src/controller/error.rs +++ b/src/controller/error.rs @@ -3,7 +3,6 @@ use hyper::body::Bytes; use hyper::header::CACHE_CONTROL; use hyper::Response; use std::collections::HashMap; -use tera::{Context, Tera}; use crate::controller::utils; use crate::controller::wallet::Wallet; @@ -24,14 +23,15 @@ pub fn error( pub fn template( assets: &HashMap<String, String>, - templates: &Tera, + templates: &minijinja::Environment<'_>, title: &str, message: &str, ) -> String { - let mut context = Context::new(); - context.insert("title", title); - context.insert("message", message); - context.insert("assets", assets); + let context = minijinja::context!( + title => title, + message => message, + assets => assets + ); - templates.render("error.html", &context).unwrap() + templates.render_str("error.html", &context).unwrap() } diff --git a/src/controller/incomes.rs b/src/controller/incomes.rs index f22098b..ac3a332 100644 --- a/src/controller/incomes.rs +++ b/src/controller/incomes.rs @@ -4,7 +4,6 @@ use http_body_util::Full; use hyper::body::Bytes; use hyper::Response; use std::collections::HashMap; -use tera::Context; use crate::controller::utils; use crate::controller::wallet::Wallet; @@ -24,13 +23,14 @@ pub async fn table( let incomes = db::incomes::list(&wallet.pool, page, PER_PAGE).await; let max_page = (count as f32 / PER_PAGE as f32).ceil() as i64; - let mut context = Context::new(); - context.insert("header", &templates::Header::Incomes); - context.insert("connected_user", &wallet.user); - context.insert("incomes", &incomes); - context.insert("page", &page); - context.insert("max_page", &max_page); - context.insert("highlight", &query.highlight); + let context = minijinja::context!( + header => templates::Header::Incomes, + connected_user => wallet.user, + incomes => incomes, + page => page, + max_page => max_page, + highlight => query.highlight + ); utils::template( &wallet.assets, @@ -70,15 +70,16 @@ async fn create_form_feedback( ) -> Response<Full<Bytes>> { let users = db::users::list(&wallet.pool).await; - let mut context = Context::new(); - context.insert("header", &templates::Header::Incomes); - context.insert("connected_user", &wallet.user); - context.insert("users", &users); - context.insert("query", &query); - context.insert("current_month", &Utc::now().date_naive().month()); - context.insert("months", &MONTHS); - context.insert("form", &form); - context.insert("error", &error); + let context = minijinja::context!( + header => templates::Header::Incomes, + connected_user => wallet.user, + users => users, + query => query, + current_month => Utc::now().date_naive().month(), + months => MONTHS, + form => form, + error => error, + ); utils::template( &wallet.assets, @@ -144,16 +145,17 @@ async fn update_form_feedback( let users = db::users::list(&wallet.pool).await; let income = db::incomes::get(&wallet.pool, id).await; - let mut context = Context::new(); - context.insert("header", &templates::Header::Incomes); - context.insert("connected_user", &wallet.user); - context.insert("users", &users); - context.insert("id", &id); - context.insert("income", &income); - context.insert("query", &query); - context.insert("months", &MONTHS); - context.insert("form", &form); - context.insert("error", &error); + let context = minijinja::context!( + header => &templates::Header::Incomes, + connected_user => &wallet.user, + users => &users, + id => &id, + income => &income, + query => &query, + months => &MONTHS, + form => &form, + error => &error + ); utils::template( &wallet.assets, diff --git a/src/controller/login.rs b/src/controller/login.rs index a1bf466..31370cc 100644 --- a/src/controller/login.rs +++ b/src/controller/login.rs @@ -5,7 +5,6 @@ use hyper::header::SET_COOKIE; use hyper::Response; use sqlx::sqlite::SqlitePool; use std::collections::HashMap; -use tera::{Context, Tera}; use crate::controller::utils::with_headers; use crate::controller::wallet::Wallet; @@ -18,14 +17,15 @@ use crate::validation; pub async fn page( assets: &HashMap<String, String>, - templates: &Tera, + templates: &minijinja::Environment<'_>, error: Option<&str>, ) -> Response<Full<Bytes>> { let connected_user: Option<User> = None; - let mut context = Context::new(); - context.insert("connected_user", &connected_user); - context.insert("error", &error); + let context = minijinja::context!( + connected_user => &connected_user, + error => &error + ); utils::template(assets, templates, "login.html", context) } @@ -33,7 +33,7 @@ pub async fn page( pub async fn login( config: &Config, assets: &HashMap<String, String>, - templates: &Tera, + templates: &minijinja::Environment<'_>, form: HashMap<String, String>, pool: SqlitePool, ) -> Response<Full<Bytes>> { @@ -75,7 +75,10 @@ pub async fn login( } Ok(false) => not_authorized(assets, templates).await, Err(err) => { - log::error!("Error verifying bcrypt password: {:?}", err); + log::error!( + "Error verifying bcrypt password: {:?}", + err + ); server_error(assets, templates, "Erreur serveur").await } }, @@ -88,7 +91,7 @@ pub async fn login( async fn server_error( assets: &HashMap<String, String>, - templates: &Tera, + templates: &minijinja::Environment<'_>, msg: &str, ) -> Response<Full<Bytes>> { page(assets, templates, Some(msg)).await @@ -96,7 +99,7 @@ async fn server_error( async fn not_authorized( assets: &HashMap<String, String>, - templates: &Tera, + templates: &minijinja::Environment<'_>, ) -> Response<Full<Bytes>> { page( assets, diff --git a/src/controller/payments.rs b/src/controller/payments.rs index 8184015..b5c0256 100644 --- a/src/controller/payments.rs +++ b/src/controller/payments.rs @@ -3,7 +3,6 @@ use hyper::body::Bytes; use hyper::header::CONTENT_TYPE; use hyper::Response; use std::collections::HashMap; -use tera::Context; use crate::controller::utils; use crate::controller::wallet::Wallet; @@ -27,17 +26,18 @@ pub async fn table( let users = db::users::list(&wallet.pool).await; let categories = db::categories::list(&wallet.pool).await; - let mut context = Context::new(); - context.insert("header", &templates::Header::Payments); - context.insert("connected_user", &wallet.user); - context.insert("payments", &payments); - context.insert("page", &page); - context.insert("max_page", &max_page); - context.insert("query", &query); - context.insert("count", &count.count); - context.insert("total_cost", &count.total_cost); - context.insert("users", &users); - context.insert("categories", &categories); + let context = minijinja::context!( + header => templates::Header::Payments, + connected_user => wallet.user, + payments => payments, + page => page, + max_page => max_page, + query => query, + count => count.count, + total_cost => count.total_cost, + users => users, + categories => categories + ); utils::template( &wallet.assets, @@ -63,14 +63,15 @@ async fn create_form_feedback( let users = db::users::list(&wallet.pool).await; let categories = db::categories::list(&wallet.pool).await; - let mut context = Context::new(); - context.insert("header", &templates::Header::Payments); - context.insert("connected_user", &wallet.user); - context.insert("users", &users); - context.insert("categories", &categories); - context.insert("query", &query); - context.insert("form", &form); - context.insert("error", &error); + let context = minijinja::context!( + header => templates::Header::Payments, + connected_user => wallet.user, + users => users, + categories => categories, + query => query, + form => form, + error => error + ); utils::template( &wallet.assets, @@ -142,16 +143,17 @@ async fn update_form_feedback( let users = db::users::list(&wallet.pool).await; let categories = db::categories::list(&wallet.pool).await; - let mut context = Context::new(); - context.insert("header", &templates::Header::Payments); - context.insert("connected_user", &wallet.user); - context.insert("id", &id); - context.insert("payment", &payment); - context.insert("users", &users); - context.insert("categories", &categories); - context.insert("query", &query); - context.insert("form", &form); - context.insert("error", &error); + let context = minijinja::context!( + header => templates::Header::Payments, + connected_user => wallet.user, + id => id, + payment => payment, + users => users, + categories => categories, + query => query, + form => form, + error => error + ); utils::template( &wallet.assets, diff --git a/src/controller/statistics.rs b/src/controller/statistics.rs index eb1e704..e57e2be 100644 --- a/src/controller/statistics.rs +++ b/src/controller/statistics.rs @@ -1,7 +1,6 @@ use http_body_util::Full; use hyper::body::Bytes; use hyper::Response; -use tera::Context; use crate::controller::utils; use crate::controller::wallet::Wallet; @@ -13,15 +12,13 @@ pub async fn get(wallet: &Wallet) -> Response<Full<Bytes>> { let payments = db::payments::list_for_stats(&wallet.pool).await; let incomes = db::incomes::total_each_month(&wallet.pool).await; - let mut context = Context::new(); - context.insert("header", &templates::Header::Statistics); - context.insert("connected_user", &wallet.user); - context.insert( - "json_categories", - &serde_json::to_string(&categories).unwrap(), + let context = minijinja::context!( + header => templates::Header::Statistics, + connected_user => wallet.user, + json_categories => serde_json::to_string(&categories).unwrap(), + json_payments => serde_json::to_string(&payments).unwrap(), + json_incomes => serde_json::to_string(&incomes).unwrap() ); - context.insert("json_payments", &serde_json::to_string(&payments).unwrap()); - context.insert("json_incomes", &serde_json::to_string(&incomes).unwrap()); utils::template( &wallet.assets, diff --git a/src/controller/utils.rs b/src/controller/utils.rs index 1b58c68..340a5c7 100644 --- a/src/controller/utils.rs +++ b/src/controller/utils.rs @@ -5,7 +5,6 @@ use hyper::header::{ }; use hyper::{Response, StatusCode}; use std::collections::HashMap; -use tera::{Context, Tera}; use crate::controller::error; @@ -23,29 +22,45 @@ pub fn with_headers( pub fn template( assets: &HashMap<String, String>, - templates: &Tera, + templates: &minijinja::Environment<'_>, path: &str, - context: Context, + context: minijinja::Value, ) -> Response<Full<Bytes>> { - let mut context = context; - context.insert("assets", assets); + let context = minijinja::context! { ..context, ..minijinja::context! { + assets => assets + }}; - match templates.render(path, &context) { + match render_template(templates, path, context) { Ok(template) => with_headers( Response::new(template.into()), vec![(CONTENT_TYPE, "text/html"), (CACHE_CONTROL, "no-cache")], ), - Err(err) => server_error( - assets, - templates, - &format!("Erreur lors de la préparation de la page : {:?}", err), - ), + Err(err) => { + log::error!("ERROR template rendering {}\n{:?}", path, err); + server_error( + assets, + templates, + &format!( + "Erreur lors de la préparation de la page : {:?}", + err + ), + ) + } } } +fn render_template( + templates: &minijinja::Environment<'_>, + name: &str, + context: minijinja::Value, +) -> Result<String, minijinja::Error> { + let template = templates.get_template(name)?; + template.render(context) +} + fn server_error( assets: &HashMap<String, String>, - templates: &Tera, + templates: &minijinja::Environment<'_>, msg: &str, ) -> Response<Full<Bytes>> { with_headers( diff --git a/src/controller/wallet.rs b/src/controller/wallet.rs index 2a4a593..7537406 100644 --- a/src/controller/wallet.rs +++ b/src/controller/wallet.rs @@ -1,6 +1,5 @@ use sqlx::sqlite::SqlitePool; use std::collections::HashMap; -use tera::Tera; use crate::model::user::User; @@ -8,6 +7,6 @@ use crate::model::user::User; pub struct Wallet { pub pool: SqlitePool, pub assets: HashMap<String, String>, - pub templates: Tera, + pub templates: minijinja::Environment<'static>, pub user: User, } diff --git a/src/db/jobs.rs b/src/db/jobs.rs index a80ef68..7d9386a 100644 --- a/src/db/jobs.rs +++ b/src/db/jobs.rs @@ -48,6 +48,8 @@ WHERE match res { Ok(_) => (), - Err(err) => log::error!("Error actualizing job last execution: {:?}", err), + Err(err) => { + log::error!("Error actualizing job last execution: {:?}", err) + } } } diff --git a/src/db/payments.rs b/src/db/payments.rs index b415a28..25b10f4 100644 --- a/src/db/payments.rs +++ b/src/db/payments.rs @@ -495,7 +495,8 @@ ORDER BY Err(err) => { log::error!( "Error looking for the category of {}: {:?}", - payment_name, err + payment_name, + err ); None } @@ -523,7 +524,8 @@ LIMIT Err(err) => { log::error!( "Error looking if category {} is used: {:?}", - category_id, err + category_id, + err ); false } diff --git a/src/jobs/mod.rs b/src/jobs/mod.rs index 17df58c..a718d93 100644 --- a/src/jobs/mod.rs +++ b/src/jobs/mod.rs @@ -1,14 +1,17 @@ mod weekly_report; use sqlx::sqlite::SqlitePool; -use tera::Tera; use tokio::time::{sleep, Duration}; use crate::db; use crate::model::config::Config; use crate::model::job::Job; -pub async fn start(config: Config, pool: SqlitePool, templates: Tera) { +pub async fn start( + config: Config, + pool: SqlitePool, + templates: minijinja::Environment<'_>, +) { loop { if db::jobs::should_run(&pool, Job::WeeklyReport).await { log::info!("Starting weekly report job"); diff --git a/src/jobs/weekly_report.rs b/src/jobs/weekly_report.rs index 0c10143..5058c52 100644 --- a/src/jobs/weekly_report.rs +++ b/src/jobs/weekly_report.rs @@ -1,6 +1,5 @@ use sqlx::sqlite::SqlitePool; use std::collections::HashMap; -use tera::{Context, Tera}; use crate::db; use crate::mail; @@ -10,9 +9,9 @@ use crate::payer; pub async fn send( config: &Config, pool: &SqlitePool, - templates: &Tera, + env: &minijinja::Environment<'_>, ) -> bool { - match get_weekly_report(pool, templates).await { + match get_weekly_report(pool, env).await { Ok(report) => { let users = db::users::list(pool).await; mail::send( @@ -30,7 +29,10 @@ pub async fn send( .await } Err(err) => { - log::error!("Error preparing weekly report from template: {:?}", err); + log::error!( + "Error preparing weekly report from template: {:?}", + err + ); false } } @@ -38,8 +40,8 @@ pub async fn send( async fn get_weekly_report( pool: &SqlitePool, - templates: &Tera, -) -> Result<String, tera::Error> { + env: &minijinja::Environment<'_>, +) -> Result<String, minijinja::Error> { let users = db::users::list(pool).await; let incomes_from = db::incomes::defined_for_all(pool).await; let user_incomes = match incomes_from { @@ -53,10 +55,11 @@ async fn get_weekly_report( let last_week_payments = db::payments::last_week(pool).await; let last_week_incomes = db::incomes::last_week(pool).await; - let mut context = Context::new(); - context.insert("exceeding_payers", &exceeding_payers); - context.insert("payments", &last_week_payments); - context.insert("incomes", &last_week_incomes); - - templates.render("report/report.j2", &context) + let template = env.get_template("report/report.j2")?; + template.render(minijinja::context!( + name => "John", + exceeding_payers => exceeding_payers, + payments => last_week_payments, + incomes => last_week_incomes + )) } diff --git a/src/mail.rs b/src/mail.rs index c77e2ad..b6db0cd 100644 --- a/src/mail.rs +++ b/src/mail.rs @@ -56,7 +56,9 @@ pub async fn send( true } else { match String::from_utf8(output.stderr) { - Ok(error) => log::error!("Error sending email: {}", error), + Ok(error) => { + log::error!("Error sending email: {}", error) + } _ => log::error!("Error sending email"), }; false diff --git a/src/main.rs b/src/main.rs index 2b3aebd..5fe8a94 100644 --- a/src/main.rs +++ b/src/main.rs @@ -22,7 +22,6 @@ use model::config; #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> { - env_logger::init(); let config = config::from_env() @@ -34,7 +33,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> { let assets = assets::get(); - let templates = templates::get(); + let templates = templates::get()?; tokio::spawn(jobs::start(config.clone(), pool.clone(), templates.clone())); diff --git a/src/routes.rs b/src/routes.rs index ae87d39..5f17ca5 100644 --- a/src/routes.rs +++ b/src/routes.rs @@ -5,7 +5,6 @@ use serde::Deserialize; use sqlx::sqlite::SqlitePool; use std::collections::HashMap; use std::convert::Infallible; -use tera::Tera; use url::form_urlencoded; use crate::controller; @@ -20,7 +19,7 @@ pub async fn routes( config: Config, pool: SqlitePool, assets: HashMap<String, String>, - templates: Tera, + templates: minijinja::Environment<'static>, request: Request<Incoming>, ) -> Result<Response<Full<Bytes>>, Infallible> { let method = request.method(); 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> { diff --git a/templates/balance.html b/templates/balance.html index b97ea40..c7f68e8 100644 --- a/templates/balance.html +++ b/templates/balance.html @@ -11,7 +11,7 @@ <ul class="g-Balance__ExceedingPayers"> {% for exceeding_payer in exceeding_payers %} <li class="g-Balance__ExceedingPayer"> - {{ exceeding_payer.0 }} : +{{ exceeding_payer.1 | euros() }} + {{ exceeding_payer[0] }} : +{{ exceeding_payer[1] | euros() }} </li> {% endfor %} </ul> @@ -35,14 +35,14 @@ {% for user_income in user_incomes %} <div class="g-Table__Row"> <span class="g-Table__Cell"> - {{ user_income.0 }} + {{ user_income[0] }} </span> <span class="g-Table__Cell g-Table__NumericCell"> - {{ user_income.1 | euros() }} + {{ user_income[1] | euros() }} </span> <span class="g-Table__Cell g-Table__NumericCell"> {% if total_income > 0 %} - {{ user_income.1 / total_income * 100 | round() }} % + {{ (user_income[1] / total_income * 100) | round }} % {% else %} – {% endif %} @@ -76,14 +76,14 @@ {% for user_payment in user_payments %} <div class="g-Table__Row"> <span class="g-Table__Cell"> - {{ user_payment.0 }} + {{ user_payment[0] }} </span> <span class="g-Table__Cell g-Table__NumericCell"> - {{ user_payment.1 | euros() }} + {{ user_payment[1] | euros() }} </span> <span class="g-Table__Cell g-Table__NumericCell"> {% if total_payments > 0 %} - {{ user_payment.1 / total_payments * 100 | round() }} % + {{ (user_payment[1] / total_payments * 100) | round }} % {% else %} – {% endif %} diff --git a/templates/base.html b/templates/base.html index c7dc9f0..9865e16 100644 --- a/templates/base.html +++ b/templates/base.html @@ -4,8 +4,8 @@ <meta charset="utf-8"> <meta name="viewport" content="width=device-width"> <title>Budget — {% block title %}{% endblock title %}</title> -<link rel="stylesheet" href="{{ assets | get(key="main.css") }}"> -<link rel="icon" href="{{ assets | get(key="icon.png") }}"> +<link rel="stylesheet" href="{{ assets["main.css"] }}"> +<link rel="icon" href="{{ assets["icon.png"] }}"> {% if connected_user %} <header class="g-Header"> @@ -78,5 +78,5 @@ {% block main %}{% endblock main %} </main> -<script src="{{ assets | get(key="main.js") }}"> +<script src="{{ assets["main.js"] }}"> </script> diff --git a/templates/category/create.html b/templates/category/create.html index af95e16..f5395bf 100644 --- a/templates/category/create.html +++ b/templates/category/create.html @@ -27,7 +27,7 @@ <input name="name" class="g-Form__Input" - value="{{ form.name | default(value="") }}" + value="{{ form.name or "" }}" required {% if not form %} autofocus {% endif %} /> @@ -39,7 +39,7 @@ name="color" type="color" class="g-Form__Input g-Form__InputColor" - value="{{ form.color | default(value="") }}" + value="{{ form.color or "" }}" required /> </label> diff --git a/templates/category/update.html b/templates/category/update.html index 48dda06..544c583 100644 --- a/templates/category/update.html +++ b/templates/category/update.html @@ -35,7 +35,7 @@ <input name="name" class="g-Form__Input" - value="{{ form.name | default(value=category.name) }}" + value="{{ form.name or category.name }}" required /> </label> @@ -46,7 +46,7 @@ name="color" type="color" class="g-Form__Input g-Form__InputColor" - value="{{ form.color | default(value=category.color) }}" + value="{{ form.color or category.color }}" required /> </label> diff --git a/templates/income/create.html b/templates/income/create.html index 3c899ca..a7755db 100644 --- a/templates/income/create.html +++ b/templates/income/create.html @@ -10,7 +10,7 @@ <p class="g-Paragraph"> <a class="g-Link g-Media__Large" - href="/incomes?page={{ query.page | default(value=1) }}" + href="/incomes?page={{ query.page or 1 }}" > Retour aux revenus </a> @@ -18,7 +18,7 @@ <form class="g-Form" - action="/income/create?page={{ query.page | default(value=1) }}" + action="/income/create?page={{ query.page or 1 }}" method="POST" > <h1 class="g-H1"> @@ -35,13 +35,13 @@ name="amount" type="number" class="g-Form__Input" - value="{{ form.amount | default(value="") }}" + value="{{ form.amount or "" }}" required {% if not form %} autofocus {% endif %} /> </label> - {% set user_id = form.user_id | default(value="" ~ connected_user.id) %} + {% set user_id = form.user_id or connected_user.id %} <label class="g-Form__Label"> Personne @@ -57,7 +57,7 @@ </select> </label> - {% set month_index = form.month | default(value="" ~ current_month) %} + {% set month_index = form.month or current_month %} <label class="g-Form__Label"> Mois @@ -81,7 +81,7 @@ name="year" type="number" class="g-Form__Input" - value="{{ form.year | default(value=now() | date(format="%Y")) }}" + value="{{ form.year or now("%Y") }}" required /> </label> diff --git a/templates/income/table.html b/templates/income/table.html index 60cd6e0..34ee096 100644 --- a/templates/income/table.html +++ b/templates/income/table.html @@ -18,7 +18,7 @@ <a class="g-Paragraph g-Button__Validate" - href="/income?page={{ page | default(value=1) }}" + href="/income?page={{ page or 1 }}" > Ajouter un revenu </a> @@ -33,7 +33,7 @@ {% for income in incomes %} <a class="g-Table__Row {% if highlight == income.id %} g-Table__Row--Highlight {% endif %}" - href="/income/{{ income.id }}?page={{ page | default(value=1) }}" + href="/income/{{ income.id }}?page={{ page or 1 }}" > <span class="g-Table__Cell g-Table__NumericCell"> {{ income.amount | euros() }} @@ -44,7 +44,7 @@ {% endfor %} </div> - {{ paging::paging( + {{ paging.view( url="/incomes", page=page, max_page=max_page diff --git a/templates/income/update.html b/templates/income/update.html index 855d5c4..f5f976e 100644 --- a/templates/income/update.html +++ b/templates/income/update.html @@ -10,7 +10,7 @@ <p class="g-Paragraph"> <a class="g-Link g-Media__Large" - href="/incomes?page={{ query.page | default(value=1) }}" + href="/incomes?page={{ query.page or 1 }}" > Retour aux revenus </a> @@ -39,12 +39,12 @@ name="amount" type="number" class="g-Form__Input" - value="{{ form.amount | default(value=income.amount) }}" + value="{{ form.amount or income.amount }}" required /> </label> - {% set user_id = form.user_id | default(value="" ~ income.user_id) %} + {% set user_id = form.user_id or income.user_id %} <label class="g-Form__Label"> Personne @@ -60,7 +60,7 @@ </select> </label> - {% set month_index = form.month | default(value="" ~ income.month) %} + {% set month_index = form.month or income.month %} <label class="g-Form__Label"> Mois @@ -82,7 +82,7 @@ name="year" type="number" class="g-Form__Input" - value="{{ form.year | default(value=income.year) }}" + value="{{ form.year or income.year }}" required /> </label> diff --git a/templates/macros/paging.html b/templates/macros/paging.html index 59ba617..840e8f4 100644 --- a/templates/macros/paging.html +++ b/templates/macros/paging.html @@ -1,10 +1,4 @@ -{% macro paging(url, page, max_page) %} - {% if url is containing("?") %} - {% set sign = "&" %} - {% else %} - {% set sign = "?" %} - {% endif %} - +{% macro view(url, page, max_page) %} <div class="g-Paging"> {% if page > 1 %} <a @@ -15,7 +9,7 @@ </a> <a class="g-Paging__Link g-Paging__Link--Active" - href="{{ url }}{{ sign }}page={{ page - 1 }}" + href="{{ url | with_param("page", page - 1) }}" > ❬ </a> @@ -33,13 +27,13 @@ {% if page < max_page %} <a class="g-Paging__Link g-Paging__Link--Active" - href="{{ url }}{{ sign }}page={{ page + 1 }}" + href="{{ url | with_param("page", page + 1) }}" > ❭ </a> <a class="g-Paging__Link g-Paging__Link--Active" - href="{{ url }}{{ sign }}page={{ max_page }}" + href="{{ url | with_param("page", max_page) }}" > ❭❭ </a> @@ -52,4 +46,4 @@ </span> {% endif %} </div> -{% endmacro paging %} +{% endmacro %} diff --git a/templates/payment/create.html b/templates/payment/create.html index 4ac73de..7bcc536 100644 --- a/templates/payment/create.html +++ b/templates/payment/create.html @@ -44,7 +44,7 @@ <input name="name" class="g-Form__Input" - value="{{ form.name | default(value="") }}" + value="{{ form.name or "" }}" required {% if not form %} autofocus {% endif %} /> @@ -56,12 +56,12 @@ name="cost" type="number" class="g-Form__Input" - value="{{ form.cost | default(value="") }}" + value="{{ form.cost or "" }}" required /> </label> - {% set user_id = form.user_id | default(value="" ~ connected_user.id) %} + {% set user_id = form.user_id or connected_user.id %} <label class="g-Form__Label"> Personne @@ -79,7 +79,7 @@ </select> </label> - {% set category_id = form.category_id | default(value="") %} + {% set category_id = form.category_id or "" %} <label class="g-Form__Label"> Catégorie @@ -96,7 +96,7 @@ </select> </label> - {% set date = form.date | default(value=now() | date(format="%Y-%m-%d")) %} + {% set date = form.date or now("%Y-%m-%d") %} {% if query.frequency != "Monthly" %} <label class="g-Form__Label"> @@ -120,7 +120,7 @@ <input type="hidden" name="frequency" - value="{{ query.frequency | default(value="Punctual") }}" + value="{{ query.frequency or "Punctual" }}" /> <div> diff --git a/templates/payment/table.html b/templates/payment/table.html index 450d84b..71bfb0a 100644 --- a/templates/payment/table.html +++ b/templates/payment/table.html @@ -20,7 +20,7 @@ </div> {% else %} <div class="g-Paragraph"> - {{ count | numeric }} paiement{{ count | pluralize }} comptabilisant {{ total_cost | euros() }}. + {{ count | numeric }} paiement{{ pluralize(count, "paiement") }} comptabilisant {{ total_cost | euros() }}. </div> {% endif %} @@ -81,9 +81,9 @@ {{ payment.cost | euros() }} </span> <span class="g-Table__Cell">{{ payment.user }}</span> - <span + <span class="g-Table__Cell g-Media__Large" - is="colored-category" + is="colored-category" data-color="{{ payment.category_color }}" > {{ payment.category_name }} @@ -97,7 +97,7 @@ {% endfor %} </div> - {{ paging::paging( + {{ paging.view( url="/" ~ payments_params( frequency=query.frequency, name=query.name, diff --git a/templates/payment/table/search.html b/templates/payment/table/search.html index 9fedb78..cb72282 100644 --- a/templates/payment/table/search.html +++ b/templates/payment/table/search.html @@ -17,7 +17,7 @@ type="search" name="name" class="g-Form__Input" - value="{{ query.name }}" + value="{{ query.name or '' }}" /> </label> @@ -27,7 +27,7 @@ type="number" name="cost" class="g-Form__Input" - value="{{ query.cost }}" + value="{{ query.cost or '' }}" /> </label> @@ -67,7 +67,7 @@ type="date" name="start_date" class="g-Form__Input" - value="{{ query.start_date }}" + value="{{ query.start_date or '' }}" /> </label> @@ -77,7 +77,7 @@ type="date" name="end_date" class="g-Form__Input" - value="{{ query.end_date }}" + value="{{ query.end_date or '' }}" /> </label> diff --git a/templates/payment/update.html b/templates/payment/update.html index 22a4d01..dfa0892 100644 --- a/templates/payment/update.html +++ b/templates/payment/update.html @@ -57,7 +57,7 @@ <input name="name" class="g-Form__Input" - value="{{ form.name | default(value=payment.name) }}" + value="{{ form.name or payment.name }}" required /> </label> @@ -68,12 +68,12 @@ name="cost" type="number" class="g-Form__Input" - value="{{ form.cost | default(value=payment.cost) }}" + value="{{ form.cost or payment.cost }}" required /> </label> - {% set user_id = form.user_id | default(value="" ~ payment.user_id) %} + {% set user_id = form.user_id or payment.user_id %} <label class="g-Form__Label"> Personne @@ -89,7 +89,7 @@ </select> </label> - {% set category_id = form.category_id | default(value="" ~ payment.category_id) %} + {% set category_id = form.category_id or payment.category_id %} <label class="g-Form__Label"> Catégorie @@ -105,7 +105,7 @@ </select> </label> - {% set date = form.date | default(value=payment.date) %} + {% set date = form.date or payment.date %} {% if payment.frequency == "Punctual" %} <label class="g-Form__Label"> diff --git a/templates/report/list.j2 b/templates/report/list.j2 index ef53244..d683879 100644 --- a/templates/report/list.j2 +++ b/templates/report/list.j2 @@ -2,13 +2,13 @@ {% if xs -%} - {% set s = xs | length | pluralize -%} + {% set l = xs | length %} - {{ xs | length }} {{ resource }}{{ s }} {{ action }}{{ s }} : + {{ xs | length }} {{ pluralize(l, resource) }} {{ pluralize(l, action) }} : {% for x in xs -%} - {{ x.date }} {{ x.name }} {{ x.amount | euros() }} {% endfor %} {% endif -%} -{% endmacro paging %} +{% endmacro %} diff --git a/templates/report/report.j2 b/templates/report/report.j2 index d36f3ce..8711184 100644 --- a/templates/report/report.j2 +++ b/templates/report/report.j2 @@ -5,7 +5,7 @@ Équilibre : {% for exceeding_payer in exceeding_payers -%} - - {{ exceeding_payer.0 }} : +{{ exceeding_payer.1 | euros() }} + - {{ exceeding_payer[0] }} : +{{ exceeding_payer[1] | euros() }} {% endfor %} {% else -%} @@ -13,38 +13,38 @@ {% endif %}{# -#}{{ list::list( +#}{{ list.list( resource="paiement", action="créé", - xs=payments | filter(attribute="action", value="Created") + xs=payments | filter("action", "Created") ) }}{# -#}{{ list::list( +#}{{ list.list( resource="paiement", action="modifié", - xs=payments | filter(attribute="action", value="Updated") + xs=payments | filter("action", "Updated") ) }}{# -#}{{ list::list( +#}{{ list.list( resource="paiement", action="supprimé", - xs=payments | filter(attribute="action", value="Deleted") + xs=payments | filter("action", "Deleted") ) }}{# -#}{{ list::list( +#}{{ list.list( resource="revenu", action="créé", - xs=incomes | filter(attribute="action", value="Created") + xs=incomes | filter("action", "Created") ) }}{# -#}{{ list::list( +#}{{ list.list( resource="revenu", action="modifié", - xs=incomes | filter(attribute="action", value="Updated") + xs=incomes | filter("action", "Updated") ) }}{# -#}{{ list::list( +#}{{ list.list( resource="revenu", action="supprimé", - xs=incomes | filter(attribute="action", value="Deleted") + xs=incomes | filter("action", "Deleted") ) }} diff --git a/templates/statistics.html b/templates/statistics.html index 21e8fcd..8f9b673 100644 --- a/templates/statistics.html +++ b/templates/statistics.html @@ -25,7 +25,7 @@ {{ json_payments }} </div> - <script src="{{ assets | get(key="chart.js") }}"> + <script src="{{ assets["chart.js"] }}"> </script> {% endblock main %} |