aboutsummaryrefslogtreecommitdiffstats
path: root/src/atom.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/atom.rs')
-rw-r--r--src/atom.rs142
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
+}