diff options
author | cel 🌸 <cel@blos.sm> | 2023-06-22 21:37:10 +0100 |
---|---|---|
committer | cel 🌸 <cel@blos.sm> | 2023-06-22 21:37:10 +0100 |
commit | ab529917847641190f21129804bbda1784b4f998 (patch) | |
tree | dfdd39286d330dd62339ade0499471b70187ae04 /src | |
parent | bc5ac494c6162743810b9aeb1cda4f22d94a486a (diff) | |
download | blossom-ab529917847641190f21129804bbda1784b4f998.tar.gz blossom-ab529917847641190f21129804bbda1784b4f998.tar.bz2 blossom-ab529917847641190f21129804bbda1784b4f998.zip |
implement atom syndication
Diffstat (limited to 'src')
-rw-r--r-- | src/error.rs | 16 | ||||
-rw-r--r-- | src/main.rs | 16 | ||||
-rw-r--r-- | src/posts/mod.rs | 1 | ||||
-rw-r--r-- | src/posts/syndication.rs | 96 |
4 files changed, 127 insertions, 2 deletions
diff --git a/src/error.rs b/src/error.rs index eb6f6e6..42c01b1 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,3 +1,5 @@ +use std::string::FromUtf8Error; + use rocket::{http::Status, Responder}; #[derive(Responder, Debug)] @@ -8,6 +10,8 @@ pub enum BlossomError { Chrono(Status, #[response(ignore)] chrono::ParseError), Io(Status, #[response(ignore)] std::io::Error), Deserialization(Status, #[response(ignore)] toml::de::Error), + Syndicator(Status, #[response(ignore)] atom_syndication::Error), + Utf8Conversion(Status, #[response(ignore)] FromUtf8Error), NotFound(Status), NoMetadata(Status), Unimplemented(Status), @@ -48,3 +52,15 @@ impl From<toml::de::Error> for BlossomError { BlossomError::Deserialization(Status::new(500), e) } } + +impl From<atom_syndication::Error> for BlossomError { + fn from(e: atom_syndication::Error) -> Self { + BlossomError::Syndicator(Status::new(500), e) + } +} + +impl From<FromUtf8Error> for BlossomError { + fn from(e: FromUtf8Error) -> Self { + BlossomError::Utf8Conversion(Status::new(500), e) + } +} diff --git a/src/main.rs b/src/main.rs index 40f546d..844f3aa 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,8 +7,9 @@ mod skweets; use std::borrow::Cow; use std::collections::HashSet; +use atom_syndication::Feed; use rocket::fs::{relative, FileServer}; -use rocket::http::Status; +use rocket::http::{ContentType, Status}; use rocket::{Request, State}; use rocket_dyn_templates::{context, Template}; @@ -87,6 +88,17 @@ async fn blog(filter: Vec<String>) -> Result<Template> { )) } +#[get("/feed")] +async fn feed() -> Result<(Status, (ContentType, String))> { + let posts = posts::get_blogposts().await?; + let feed = posts::syndication::atom(posts).await; + let feed: String = String::from_utf8(feed.write_to(Vec::new())?)?; + Ok(( + Status::new(200), + (ContentType::new("application", "atom+xml"), feed), + )) +} + #[get("/contact")] async fn contact() -> Template { Template::render("contact", context! {}) @@ -130,7 +142,7 @@ async fn main() -> std::result::Result<(), rocket::Error> { .attach(Template::custom(|engines| { engines.tera.autoescape_on(vec![]); })) - .mount("/", routes![home, contact, blog, blogpost, plants]) + .mount("/", routes![home, contact, blog, blogpost, feed, plants]) .register("/", catchers![catcher]) .mount("/", FileServer::from(relative!("static"))) .launch() diff --git a/src/posts/mod.rs b/src/posts/mod.rs index 2dc5c4b..7f8e6c4 100644 --- a/src/posts/mod.rs +++ b/src/posts/mod.rs @@ -1,5 +1,6 @@ mod article; mod note; +pub mod syndication; use std::collections::HashSet; diff --git a/src/posts/syndication.rs b/src/posts/syndication.rs new file mode 100644 index 0000000..f6f0b17 --- /dev/null +++ b/src/posts/syndication.rs @@ -0,0 +1,96 @@ +use atom_syndication::{Category, Content, Entry, Feed, Generator, Link, Person, Text, TextType}; + +use super::{Article, Post}; + +pub async fn atom(posts: Vec<Post<Article>>) -> Feed { + let me = Person { + name: "cel".into(), + email: Some("cel@blos.sm".into()), + uri: Some("https://blos.sm".into()), + }; + let mut authors = Vec::new(); + authors.push(me); + let link = Link { + href: "https://blos.sm/feed".into(), + rel: "self".into(), + hreflang: Some("en".into()), + mime_type: Some("application/atom+xml".into()), + title: Some("atom feed".into()), + length: None, + }; + let mut links = Vec::new(); + links.push(link); + let mut feed = Feed { + title: Text { + value: "cel's site".into(), + base: None, + lang: Some("en".into()), + r#type: TextType::Text, + }, + id: "https://blos.sm".into(), + updated: posts[0].created_at.into(), + authors: authors.clone(), + categories: Vec::new(), + contributors: authors.clone(), + generator: Some(Generator { + value: "blos.sm".into(), + uri: Some("https://bunny.garden/cel/blos.sm".into()), + version: None, + }), + icon: Some("/icon.png".into()), + links: links.clone(), + logo: Some("/logo.png".into()), + rights: None, + subtitle: None, + entries: Vec::new(), + base: Some("https://blos.sm".into()), + lang: Some("en".into()), + ..Default::default() + }; + for mut post in posts { + post.render().await.unwrap_or_default(); + let mut id = String::from("https://blos.sm/blog/"); + id.push_str(&post.data.name); + let categories = post + .tags + .into_iter() + .map(|tag| Category { + term: tag.clone(), + scheme: None, + label: Some(tag.clone()), + }) + .collect(); + let entry = Entry { + title: Text { + value: post.subject.unwrap_or_default(), + base: None, + lang: Some("en".into()), + r#type: TextType::Text, + }, + id: id.clone(), + updated: if let Some(updated_at) = post.updated_at { + updated_at.into() + } else { + post.created_at.into() + }, + authors: authors.clone(), + categories, + contributors: authors.clone(), + links: links.clone(), + published: Some(post.created_at.into()), + rights: None, + source: None, + summary: None, + content: Some(Content { + base: None, + lang: Some("en".into()), + value: post.render, + src: Some(id), + content_type: Some("html".to_string()), + }), + ..Default::default() + }; + feed.entries.push(entry); + } + feed +} |