Skip to content

Commit

Permalink
Add chrono dependency, list of events and add a change to initialize …
Browse files Browse the repository at this point in the history
…tera priort to AppState to register filters for templating
  • Loading branch information
RileyChampion committed Dec 27, 2024
1 parent d14f668 commit 2131d5d
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 5 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
57 changes: 53 additions & 4 deletions src/app/mod.rs
Original file line number Diff line number Diff line change
@@ -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::{
Expand All @@ -25,10 +27,33 @@ struct AppState {
mail: Email,
}

fn format_datetime(value: &Value, args: &HashMap<String, Value>) -> tera::Result<Value> {
// 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<Utc>
let datetime: DateTime<Utc> = 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<Router> {
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?,
};
Expand All @@ -41,6 +66,7 @@ pub async fn build(config: Config) -> Result<Router> {
.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))
Expand Down Expand Up @@ -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<Arc<AppState>>,
Query(param): Query<EventsParam>,
) -> AppResult<Response> {
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<Arc<AppState>>) -> AppResult<Response> {
let ctx = tera::Context::new();
let html = state.templates.render("event-create.tera.html", &ctx).unwrap();
Expand Down Expand Up @@ -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())
}

Expand Down
15 changes: 15 additions & 0 deletions src/utils/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,21 @@ impl Db {
.await?;
Ok(event)
}
// Get all Events
pub async fn get_all_events(&self, date: String, past: bool) -> Result<Vec<Event>, 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,
Expand Down
35 changes: 35 additions & 0 deletions templates/event-list.tera.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WLSD</title>
</head>
<body>
<style>
body {
background-color: #000;
color: #fff;
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
}
.event-card a {
padding: 5px 10px;
text-decoration: none;
color: inherit;
font-size: 18px;
}
.event-card a:hover {
color: #a7a5a1;
/* border-color: #a7a5a1; */
}
</style>
<h1>Upcoming Events:</h1>
{% for event in events %}
<div key="event-{{event.id}}" class="event-card">
<a href="/event/{{event.id}}">{{event.start_date | format_datetime(format="%d.%m.%Y")}} | {{ event.title }}</a>
</div>
{% endfor %}
</body>
</html>
File renamed without changes.

0 comments on commit 2131d5d

Please sign in to comment.