aboutsummaryrefslogblamecommitdiffstats
path: root/src/atom.rs
blob: 6e2cd1a32eab2480528d05afd2f52b6a32700f23 (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: AsRef<dyn Post + Send + Sync>>(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
            .iter()
            .fold(DateTime::<Utc>::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("/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
            .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
}