aboutsummaryrefslogblamecommitdiffstats
path: root/src/atom.rs
blob: 4410edb9ef280405c67b6a9cfe8b1bc474de5953 (plain) (tree)













































































































































                                                                                              
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
}