use crate::startup::AppState; use askama::Template; use axum::{ extract::{Path, State}, response::{Html, IntoResponse, Response}, }; use chrono::{DateTime, Utc}; use reqwest::StatusCode; use sqlx::PgPool; use uuid::Uuid; struct PostEntry { post_id: Uuid, author: Option, title: String, content: String, published_at: DateTime, } impl PostEntry { #[allow(dead_code)] fn formatted_date(&self) -> String { self.published_at.format("%B %d, %Y").to_string() } } #[derive(Template)] #[template(path = "../templates/posts.html")] struct PostsTemplate { posts: Vec, } #[derive(Template)] #[template(path = "../templates/post.html")] struct PostTemplate { post: PostEntry, } pub async fn list_posts( State(AppState { connection_pool, .. }): State, ) -> Response { match get_latest_posts(&connection_pool, 5).await { Err(e) => { tracing::error!("Could not fetch latest posts: {}", e); StatusCode::INTERNAL_SERVER_ERROR.into_response() } Ok(posts) => { let template = PostsTemplate { posts }; Html(template.render().unwrap()).into_response() } } } async fn get_latest_posts(connection_pool: &PgPool, n: i64) -> Result, sqlx::Error> { sqlx::query_as!( PostEntry, r#" SELECT p.post_id, u.username AS author, p.title, p.content, p.published_at FROM posts p LEFT JOIN users u ON p.author_id = u.user_id ORDER BY p.published_at DESC LIMIT $1 "#, n ) .fetch_all(connection_pool) .await } pub async fn see_post( State(AppState { connection_pool, .. }): State, Path(post_id): Path, ) -> Response { match get_post(&connection_pool, post_id).await { Err(e) => { tracing::error!("Could not fetch post #{}: {}", post_id, e); StatusCode::INTERNAL_SERVER_ERROR.into_response() } Ok(post) => { let template = PostTemplate { post }; Html(template.render().unwrap()).into_response() } } } async fn get_post(connection_pool: &PgPool, post_id: Uuid) -> Result { sqlx::query_as!( PostEntry, r#" SELECT p.post_id, u.username AS author, p.title, p.content, p.published_at FROM posts p LEFT JOIN users u ON p.author_id = u.user_id WHERE p.post_id = $1 "#, post_id ) .fetch_one(connection_pool) .await }