103 lines
3.5 KiB
Rust
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())
|
|
}
|