From 24eeb54a6b7159964e8887ade7fa5173b50feb3a Mon Sep 17 00:00:00 2001 From: Joris Date: Sun, 26 Jan 2025 17:58:57 +0100 Subject: Replace tera by minijinja tera was doing the job all right, but minijinja has fewer dependencies. --- Cargo.lock | 345 +++--------------------------------- Cargo.toml | 2 +- src/assets.rs | 2 +- src/controller/balance.rs | 21 +-- src/controller/categories.rs | 40 +++-- src/controller/error.rs | 14 +- src/controller/incomes.rs | 56 +++--- src/controller/login.rs | 21 ++- src/controller/payments.rs | 62 +++---- src/controller/statistics.rs | 15 +- src/controller/utils.rs | 39 ++-- src/controller/wallet.rs | 3 +- src/db/jobs.rs | 4 +- src/db/payments.rs | 6 +- src/jobs/mod.rs | 7 +- src/jobs/weekly_report.rs | 27 +-- src/mail.rs | 4 +- src/main.rs | 3 +- src/routes.rs | 3 +- src/templates.rs | 164 +++++++++++------ templates/balance.html | 14 +- templates/base.html | 6 +- templates/category/create.html | 4 +- templates/category/update.html | 4 +- templates/income/create.html | 12 +- templates/income/table.html | 6 +- templates/income/update.html | 10 +- templates/macros/paging.html | 16 +- templates/payment/create.html | 12 +- templates/payment/table.html | 8 +- templates/payment/table/search.html | 8 +- templates/payment/update.html | 10 +- templates/report/list.j2 | 6 +- templates/report/report.j2 | 26 +-- templates/statistics.html | 2 +- 35 files changed, 377 insertions(+), 605 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7237130..1455ebf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -186,16 +186,6 @@ dependencies = [ "cipher", ] -[[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" @@ -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", @@ -270,28 +260,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[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" @@ -353,25 +321,6 @@ version = "2.4.0" 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" @@ -408,12 +357,6 @@ dependencies = [ "zeroize", ] -[[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" @@ -650,30 +593,6 @@ version = "0.31.1" 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" @@ -798,15 +717,6 @@ version = "1.0.3" 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" @@ -1015,22 +925,6 @@ dependencies = [ "icu_properties", ] -[[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" @@ -1148,6 +1042,23 @@ version = "2.7.4" 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" @@ -1259,15 +1170,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[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" @@ -1283,89 +1185,6 @@ version = "2.3.1" 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" @@ -1606,21 +1425,18 @@ version = "1.0.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" @@ -1712,12 +1528,6 @@ dependencies = [ "rand_core", ] -[[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" @@ -1727,16 +1537,6 @@ dependencies = [ "autocfg", ] -[[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" @@ -2028,28 +1828,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[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" @@ -2198,62 +1976,6 @@ version = "1.17.0" 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" @@ -2328,16 +2050,6 @@ version = "0.9.5" 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" @@ -2436,15 +2148,6 @@ dependencies = [ "wasite", ] -[[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" diff --git a/Cargo.toml b/Cargo.toml index 1f89362..d206b30 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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 { 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> { 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> { 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, error: Option, ) -> Response> { - 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, - 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> { 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, - templates: &Tera, + templates: &minijinja::Environment<'_>, error: Option<&str>, ) -> Response> { let connected_user: Option = 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, - templates: &Tera, + templates: &minijinja::Environment<'_>, form: HashMap, pool: SqlitePool, ) -> Response> { @@ -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, - templates: &Tera, + templates: &minijinja::Environment<'_>, msg: &str, ) -> Response> { page(assets, templates, Some(msg)).await @@ -96,7 +99,7 @@ async fn server_error( async fn not_authorized( assets: &HashMap, - templates: &Tera, + templates: &minijinja::Environment<'_>, ) -> Response> { 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> { 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, - templates: &Tera, + templates: &minijinja::Environment<'_>, path: &str, - context: Context, + context: minijinja::Value, ) -> Response> { - 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 { + let template = templates.get_template(name)?; + template.render(context) +} + fn server_error( assets: &HashMap, - templates: &Tera, + templates: &minijinja::Environment<'_>, msg: &str, ) -> Response> { 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, - 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 { + env: &minijinja::Environment<'_>, +) -> Result { 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> { - env_logger::init(); let config = config::from_env() @@ -34,7 +33,7 @@ async fn main() -> Result<(), Box> { 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, - templates: Tera, + templates: minijinja::Environment<'static>, request: Request, ) -> Result>, 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, 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, +) -> Vec { + 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) -> Result { - 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) -> Result { - 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) -> Result { - 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, + key: &str, + value: String, +) -> Vec { + 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 { 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 @@
    {% for exceeding_payer in exceeding_payers %}
  • - {{ exceeding_payer.0 }} : +{{ exceeding_payer.1 | euros() }} + {{ exceeding_payer[0] }} : +{{ exceeding_payer[1] | euros() }}
  • {% endfor %}
@@ -35,14 +35,14 @@ {% for user_income in user_incomes %}
- {{ user_income.0 }} + {{ user_income[0] }} - {{ user_income.1 | euros() }} + {{ user_income[1] | euros() }} {% 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 %}
- {{ user_payment.0 }} + {{ user_payment[0] }} - {{ user_payment.1 | euros() }} + {{ user_payment[1] | euros() }} {% 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 @@ Budget — {% block title %}{% endblock title %} - - + + {% if connected_user %}
@@ -78,5 +78,5 @@ {% block main %}{% endblock main %} - 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 @@ @@ -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 /> 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 @@ @@ -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 /> 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 @@

Retour aux revenus @@ -18,7 +18,7 @@

@@ -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 %} /> - {% set user_id = form.user_id | default(value="" ~ connected_user.id) %} + {% set user_id = form.user_id or connected_user.id %} - {% set month_index = form.month | default(value="" ~ current_month) %} + {% set month_index = form.month or current_month %} 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 @@ Ajouter un revenu @@ -33,7 +33,7 @@ {% for income in incomes %} {{ income.amount | euros() }} @@ -44,7 +44,7 @@ {% endfor %}

- {{ 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 @@

Retour aux revenus @@ -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 /> - {% set user_id = form.user_id | default(value="" ~ income.user_id) %} + {% set user_id = form.user_id or income.user_id %} - {% set month_index = form.month | default(value="" ~ income.month) %} + {% set month_index = form.month or income.month %} 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) %}

{% if page > 1 %} @@ -33,13 +27,13 @@ {% if page < max_page %} ❭❭ @@ -52,4 +46,4 @@ {% endif %}
-{% 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 @@ @@ -56,12 +56,12 @@ name="cost" type="number" class="g-Form__Input" - value="{{ form.cost | default(value="") }}" + value="{{ form.cost or "" }}" required /> - {% set user_id = form.user_id | default(value="" ~ connected_user.id) %} + {% set user_id = form.user_id or connected_user.id %} - {% set category_id = form.category_id | default(value="") %} + {% set category_id = form.category_id or "" %} - {% 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" %}
{{ payment.user }} - {{ payment.category_name }} @@ -97,7 +97,7 @@ {% endfor %}
- {{ 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 '' }}" /> @@ -27,7 +27,7 @@ type="number" name="cost" class="g-Form__Input" - value="{{ query.cost }}" + value="{{ query.cost or '' }}" /> @@ -67,7 +67,7 @@ type="date" name="start_date" class="g-Form__Input" - value="{{ query.start_date }}" + value="{{ query.start_date or '' }}" /> @@ -77,7 +77,7 @@ type="date" name="end_date" class="g-Form__Input" - value="{{ query.end_date }}" + value="{{ query.end_date or '' }}" /> 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 @@ @@ -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 /> - {% set user_id = form.user_id | default(value="" ~ payment.user_id) %} + {% set user_id = form.user_id or payment.user_id %} - {% set category_id = form.category_id | default(value="" ~ payment.category_id) %} + {% set category_id = form.category_id or payment.category_id %} - {% set date = form.date | default(value=payment.date) %} + {% set date = form.date or payment.date %} {% if payment.frequency == "Punctual" %}