package main import ( "cmp" "encoding/xml" "net/http" "time" ) const feedItems = 20 type rss struct { XMLName xml.Name `xml:"rss"` Version string `xml:"version,attr"` DC string `xml:"xmlns:dc,attr"` // Dublin Core, for dc:creator Channel rssChannel `xml:"channel"` } type rssChannel struct { Title string `xml:"title"` Link string `xml:"link"` Description string `xml:"description"` LastBuildDate string `xml:"lastBuildDate,omitempty"` Items []rssItem `xml:"item"` } type rssItem struct { Title string `xml:"title"` Link string `xml:"link"` GUID string `xml:"guid"` PubDate string `xml:"pubDate"` Description string `xml:"description,omitempty"` // RSS's own must be an email address; dc:creator takes a name. Creator string `xml:"dc:creator"` } func (a *app) feed(w http.ResponseWriter, r *http.Request) { idx, err := a.store.Index() if err != nil { a.serverError(w, err) return } ch := rssChannel{ Title: a.siteName, Link: a.siteURL + "/", Description: "Posts from " + a.siteName, } defaultAuthor := a.config.Get().DefaultAuthor for i, p := range idx.posts { if i == feedItems { break } if i == 0 { ch.LastBuildDate = p.Date.Format(time.RFC1123Z) } link := a.siteURL + "/posts/" + p.Slug ch.Items = append(ch.Items, rssItem{ Title: p.Title, Link: link, GUID: link, PubDate: p.Date.Format(time.RFC1123Z), Description: p.Summary, Creator: cmp.Or(p.Author, defaultAuthor), }) } out, err := xml.MarshalIndent(rss{Version: "2.0", DC: "http://purl.org/dc/elements/1.1/", Channel: ch}, "", " ") if err != nil { a.serverError(w, err) return } w.Header().Set("Content-Type", "application/rss+xml; charset=utf-8") w.Write([]byte(xml.Header)) w.Write(out) }