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>(ctx: Context, entries: Vec

) -> 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 .iter() .fold(DateTime::::MIN_UTC, |acc, entry| { if let Some(updated_at) = entry.as_ref().updated_at() { if *updated_at > acc { *updated_at } else { acc } } else { let published_at = entry.as_ref().published_at(); if *published_at > acc { *published_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("/static/favicon.png".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 .as_ref() .tags() .into_iter() .map(|category| Category { term: category.to_string(), scheme: None, label: Some(category.to_string()), }) .collect(); let published = Some(entry.as_ref().published_at().to_owned().into()); let title = if let Some(title) = entry.as_ref().subject() { title.to_owned() } else { entry.as_ref().content()[..30].to_owned() + "..." }; let entry = AtomEntry { title: Text { value: title, base: None, lang: Some(entry.as_ref().lang().to_owned()), r#type: TextType::Text, }, id: entry.as_ref().link(), updated: (*entry .as_ref() .updated_at() .unwrap_or_else(|| entry.as_ref().published_at())) .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.as_ref().lang().to_owned()), value: Some(entry.as_ref().content().to_owned()), src: Some(entry.as_ref().link()), content_type: Some("html".to_string()), }), ..Default::default() }; feed.entries.push(entry); } feed }