diff options
Diffstat (limited to '')
-rw-r--r-- | src/atom.rs | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/src/atom.rs b/src/atom.rs new file mode 100644 index 0000000..4410edb --- /dev/null +++ b/src/atom.rs @@ -0,0 +1,142 @@ +use atom_syndication::{ + Category, Content as AtomContent, Entry as AtomEntry, Feed, Generator, Link, Person, Text, + TextType, +}; +use chrono::{DateTime, Utc}; + +use crate::posts::Post; + +pub struct Context { + /// the page for which the feed is being generated for + pub page_title: String, + /// the human-readable page the feed is for + pub page_url: String, + /// the url to the atom xml document + pub self_url: String, + /// current site language + pub lang: String, +} + +pub async fn atom<P: Post + Clone>(ctx: Context, entries: Vec<P>) -> Feed { + let mut authors = Vec::new(); + let me = Person { + name: "cel".to_owned(), + email: Some("cel@blos.sm".to_owned()), + uri: Some("/contact".to_owned()), + }; + authors.push(me.clone()); + let page_link = Link { + href: ctx.page_url.clone(), + rel: "alternate".into(), + hreflang: Some(ctx.lang.clone()), + mime_type: Some("text/html".into()), + title: Some(ctx.page_title.clone()), + length: None, + }; + let home_link = Link { + // TODO?: localisation + href: "/".into(), + rel: "via".into(), + hreflang: Some(ctx.lang.clone()), + mime_type: Some("text/html".into()), + // TODO: localisation + title: Some("cel's garden".into()), + length: None, + }; + let self_link = Link { + href: ctx.self_url.into(), + rel: "self".into(), + hreflang: Some(ctx.lang.clone()), + mime_type: Some("application/atom+xml".into()), + // TODO: localisation + title: Some("atom feed".into()), + length: None, + }; + let mut links = Vec::new(); + links.push(page_link); + links.push(home_link); + links.push(self_link); + let mut feed = Feed { + title: Text { + value: ctx.page_title, + base: None, + lang: Some(ctx.lang.clone()), + r#type: TextType::Text, + }, + id: ctx.page_url, + updated: entries + .clone() + .into_iter() + .fold(DateTime::<Utc>::MIN_UTC, |acc, entry| { + let updated_at = entry.updated_at().to_owned(); + if updated_at > acc { + updated_at + } else { + acc + } + }) + .into(), + authors: authors.clone(), + categories: Vec::new(), + contributors: authors.clone(), + generator: Some(Generator { + value: "blossom".into(), + uri: Some("https://bunny.garden/cel/blossom".into()), + version: None, + }), + icon: Some("/favicon.ico".into()), + links: links.clone(), + logo: Some("/logo.png".into()), + entries: Vec::new(), + // TODO: determine base url from lang + base: Some("https://en.blos.sm/".into()), + lang: Some(ctx.lang), + ..Default::default() + }; + for entry in entries { + // TODO: localisation: url from lang + filtering entries translated or not + let categories = entry + .tags() + .into_iter() + .map(|category| Category { + term: category.clone(), + scheme: None, + label: Some(category.clone()), + }) + .collect(); + let published = Some(entry.published_at().to_owned().into()); + let title = if let Some(title) = entry.subject() { + title.to_owned() + } else { + entry.content()[..30].to_owned() + "..." + }; + let entry = AtomEntry { + title: Text { + value: title, + base: None, + lang: Some(entry.lang().to_owned()), + r#type: TextType::Text, + }, + id: entry.link(), + updated: entry.updated_at().to_owned().into(), + authors: authors.clone(), + categories, + contributors: authors.clone(), + links: links.clone(), + published, + rights: None, + source: None, + summary: None, + content: Some(AtomContent { + base: None, + lang: Some(entry.lang().to_owned()), + value: Some(entry.content().to_owned()), + src: Some(entry.link()), + content_type: Some("html".to_string()), + }), + ..Default::default() + }; + feed.entries.push(entry); + } + feed +} |