sepiatones_xyz/src/main.rs

103 lines
3.5 KiB
Rust

#[macro_use]
extern crate rocket;
use chrono::{DateTime, Utc};
use rocket::fs::NamedFile;
use rocket_dyn_templates::{context, Template};
use scraper::{Html, Selector};
use serde::Serialize;
use std::collections::HashMap;
use std::path::Path;
#[get("/")]
fn serve_main() -> Template {
Template::render(
"index",
context! {
content: std::fs::read_to_string("data/pages/about.html").unwrap_or_else(|_| "Error loading about page.".to_string())
},
)
}
#[get("/posts/<post_name>")]
async fn serve_post(post_name: &str) -> Template {
let file_path = Path::new("data/posts").join(format!("{}.html", post_name));
let file_maybe = std::fs::read_to_string(file_path);
let file = match file_maybe.ok() {
Some(s) => s,
None => "404: File not found.".to_string(),
};
Template::render(
"index",
context! {
content: file
},
)
}
#[get("/style/<file>")]
async fn serve_css(file: &str) -> Option<NamedFile> {
let file_path = Path::new("data/style").join(format!("{}", file));
NamedFile::open(file_path).await.ok()
}
#[get("/recent_posts")]
fn list_recent_posts() -> Template {
#[derive(Serialize)]
struct Post {
title: String,
path: String,
date: String,
date_utc: DateTime<Utc>,
}
let posts_dir = Path::new("data/posts");
let mut posts = Vec::new();
if let Ok(entries) = std::fs::read_dir(posts_dir) {
for entry in entries {
if let Ok(entry) = entry {
if let Some(file_name) = entry.file_name().to_str() {
if file_name.ends_with(".html") {
let file = match std::fs::read_to_string(posts_dir.join(file_name)) {
Ok(s) => s,
Err(_) => continue,
};
let document = Html::parse_document(file.as_str());
let mut tags: HashMap<&str, &str> = HashMap::new();
for meta_tag in document.select(&Selector::parse("meta").unwrap()) {
let name = meta_tag.value().attr("name").unwrap_or("");
let content = meta_tag.value().attr("content").unwrap_or("");
tags.insert(name, content);
}
let title = tags.get("title").unwrap_or(&"Untitled Post").to_string();
let date_utc = tags
.get("date")
.and_then(|s_date| DateTime::parse_from_rfc3339(s_date).ok())
.map(|dt| dt.with_timezone(&Utc))
.unwrap_or_else(|| DateTime::from_timestamp(0, 0).unwrap());
let date = date_utc.format("%d-%m-%Y").to_string();
posts.push(Post {
title,
date_utc,
date,
path: format!("/posts/{}", file_name.trim_end_matches(".html")),
});
}
}
}
}
}
posts.sort_by_key(|post| std::cmp::Reverse(post.date_utc));
Template::render("posts_list", context! { posts: posts })
}
#[launch]
fn rocket() -> _ {
rocket::build()
.mount("/", routes![serve_post, serve_main, serve_css, list_recent_posts])
.attach(Template::fairing())
}