From 2131d5dbd103e7be43928780287da4673a1493ac Mon Sep 17 00:00:00 2001 From: RileyChampion Date: Fri, 27 Dec 2024 01:53:01 -0700 Subject: [PATCH] Add chrono dependency, list of events and add a change to initialize tera priort to AppState to register filters for templating --- Cargo.toml | 2 +- src/app/mod.rs | 57 +++++++++++++++++-- src/utils/db.rs | 15 +++++ templates/event-list.tera.html | 35 ++++++++++++ ...event-update.tera.html => event.tera.html} | 0 5 files changed, 104 insertions(+), 5 deletions(-) create mode 100644 templates/event-list.tera.html rename templates/{event-update.tera.html => event.tera.html} (100%) diff --git a/Cargo.toml b/Cargo.toml index 2edaac2..bad8f66 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ futures = "0.3" serde = { version = "1", features = ["derive"] } toml = "0.8" rand = "0.8" - +chrono = "0.4" # Add a little optimization to debug builds [profile.dev] diff --git a/src/app/mod.rs b/src/app/mod.rs index a364cef..97ff528 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -1,7 +1,9 @@ -use std::{sync::Arc, time::Duration}; +use std::{collections::HashMap, sync::Arc, time::Duration}; use crate::utils::{config::*, db::Db, email::Email}; -use tera::Tera; +use chrono::{DateTime, Local, NaiveDateTime, Utc}; +use serde::Deserialize; +use tera::{Tera, Value}; use anyhow::Result; use axum::{ @@ -25,10 +27,33 @@ struct AppState { mail: Email, } +fn format_datetime(value: &Value, args: &HashMap) -> tera::Result { + // Extract the input string from the value + let input = value.as_str().ok_or_else(|| tera::Error::msg("Value must be a string"))?; + + // Parse the input string as a NaiveDateTime + let naive_datetime = NaiveDateTime::parse_from_str(input, "%Y-%m-%dT%H:%M") + .map_err(|_| tera::Error::msg("Failed to parse date"))?; + + // Convert NaiveDateTime to DateTime + let datetime: DateTime = DateTime::from_naive_utc_and_offset(naive_datetime, Utc); + + // Check for a custom format in arguments, or use a default + let format = args.get("format").and_then(Value::as_str).unwrap_or("%m.%d.%Y"); + + // Format the date-time + let formatted = datetime.format(format).to_string(); + Ok(Value::String(formatted)) +} + pub async fn build(config: Config) -> Result { + let mut tera_templates = Tera::new("templates/*")?; + // Register fiters to use while templating + tera_templates.register_filter("format_datetime", format_datetime); + let state = AppState { config: config.clone(), - templates: Tera::new("templates/*")?, + templates: tera_templates, db: Db::connect(&config.app.db).await?, mail: Email::connect(config.email).await?, }; @@ -41,6 +66,7 @@ pub async fn build(config: Config) -> Result { .route("/register", post(register_form)) .route("/event/create", get(event_create)) .route("/event/create", post(create_event_form)) + .route("/events", get(event_list)) .route("/event/:event_id", get(event_update)) .route("/event/:event_id/update", post(update_event_form)) .route("/event/:event_id/delete", post(deleting_event)) @@ -158,6 +184,29 @@ async fn register_form( Ok(headers.into_response()) } +#[derive(Deserialize)] +struct EventsParam { + #[serde(default = "default_to_false")] + past: bool, +} +fn default_to_false() -> bool { + false +} +async fn event_list( + State(state): State>, + Query(param): Query, +) -> AppResult { + let mut ctx = tera::Context::new(); + + let events = state + .db + .get_all_events(Local::now().format("fmt").to_string(), param.past) + .await?; + ctx.insert("events", &events); + let html = state.templates.render("event-list.tera.html", &ctx).unwrap(); + Ok(Html(html).into_response()) +} + async fn event_create(State(state): State>) -> AppResult { let ctx = tera::Context::new(); let html = state.templates.render("event-create.tera.html", &ctx).unwrap(); @@ -192,7 +241,7 @@ async fn event_update( }; ctx.insert("event", &event); - let html = state.templates.render("event-update.tera.html", &ctx).unwrap(); + let html = state.templates.render("event.tera.html", &ctx).unwrap(); Ok(Html(html).into_response()) } diff --git a/src/utils/db.rs b/src/utils/db.rs index 2a8c1dc..9f004a7 100644 --- a/src/utils/db.rs +++ b/src/utils/db.rs @@ -178,6 +178,21 @@ impl Db { .await?; Ok(event) } + // Get all Events + pub async fn get_all_events(&self, date: String, past: bool) -> Result, Error> { + let events = if !past { + sqlx::query_as::<_, Event>("SELECT e.* FROM events e WHERE start_date >= ?") + .bind(date) + .fetch_all(&self.pool) + .await? + } else { + sqlx::query_as::<_, Event>("SELECT e.* FROM events e WHERE start_date < ?") + .bind(date) + .fetch_all(&self.pool) + .await? + }; + Ok(events) + } // Create Event pub async fn create_event( &self, diff --git a/templates/event-list.tera.html b/templates/event-list.tera.html new file mode 100644 index 0000000..a1982e5 --- /dev/null +++ b/templates/event-list.tera.html @@ -0,0 +1,35 @@ + + + + + + WLSD + + + +

Upcoming Events:

+ {% for event in events %} + + {% endfor %} + + \ No newline at end of file diff --git a/templates/event-update.tera.html b/templates/event.tera.html similarity index 100% rename from templates/event-update.tera.html rename to templates/event.tera.html