owl-blogs/web/rss_handler.go

139 lines
3.2 KiB
Go
Raw Normal View History

2023-06-25 19:32:36 +00:00
package web
import (
2023-07-20 17:49:52 +00:00
"bytes"
"encoding/xml"
"net/url"
2023-06-25 19:32:36 +00:00
"owl-blogs/app"
2023-07-20 17:49:52 +00:00
"owl-blogs/domain/model"
"sort"
"time"
2023-06-25 19:32:36 +00:00
"github.com/gofiber/fiber/v2"
)
2023-07-20 17:49:52 +00:00
type RSS struct {
XMLName xml.Name `xml:"rss"`
Version string `xml:"version,attr"`
2023-07-21 19:59:25 +00:00
Atom string `xml:"xmlns:atom,attr"`
2023-07-20 17:49:52 +00:00
Channel RSSChannel `xml:"channel"`
}
2023-07-21 19:40:32 +00:00
type RSSDescription struct {
XMLName xml.Name `xml:"description"`
Text string `xml:",cdata"`
}
2023-07-21 19:59:25 +00:00
type AtomLink struct {
Href string `xml:"href,attr"`
Rel string `xml:"rel,attr,omitempty"`
Type string `xml:"type,attr,omitempty"`
Title string `xml:"title,attr,omitempty"`
}
2023-07-20 17:49:52 +00:00
type RSSChannel struct {
2023-07-21 19:40:32 +00:00
Title string `xml:"title"`
Link string `xml:"link"`
2023-07-21 19:59:25 +00:00
AtomLinks []AtomLink `xml:"atom:link"`
2023-07-21 19:40:32 +00:00
Description RSSDescription `xml:"description"`
2023-07-21 20:09:48 +00:00
PubDate string `xml:"pubDate"`
LastBuild string `xml:"lastBuildDate"`
Generator string `xml:"generator"`
2023-07-21 19:40:32 +00:00
Items []RSSItem `xml:"item"`
2023-07-20 17:49:52 +00:00
}
type RSSItem struct {
2023-07-21 19:40:32 +00:00
Guid string `xml:"guid"`
Title string `xml:"title"`
Link string `xml:"link"`
PubDate string `xml:"pubDate"`
Description RSSDescription `xml:"description"`
2023-07-20 17:49:52 +00:00
}
func RenderRSSFeed(config model.SiteConfig, entries []model.Entry) (string, error) {
rss := RSS{
Version: "2.0",
2023-07-21 19:59:25 +00:00
Atom: "http://www.w3.org/2005/Atom",
2023-07-20 17:49:52 +00:00
Channel: RSSChannel{
2023-07-21 19:40:32 +00:00
Title: config.Title,
Link: config.FullUrl,
2023-07-21 19:59:25 +00:00
AtomLinks: []AtomLink{
{
Href: config.FullUrl + "/index.xml",
Rel: "self",
Type: "application/rss+xml",
},
},
2023-07-21 19:40:32 +00:00
Description: RSSDescription{
Text: config.SubTitle,
},
2023-07-21 20:09:48 +00:00
PubDate: time.Now().Format(time.RFC1123Z),
LastBuild: time.Now().Format(time.RFC1123Z),
Generator: "owl-blogs",
Items: make([]RSSItem, 0),
2023-07-20 17:49:52 +00:00
},
}
for _, entry := range entries {
content := entry.Content()
2023-07-21 19:40:32 +00:00
entryUrl, _ := url.JoinPath(config.FullUrl, "/posts/", url.PathEscape(entry.ID()), "/")
2023-07-20 17:49:52 +00:00
rss.Channel.Items = append(rss.Channel.Items, RSSItem{
2023-07-21 19:40:32 +00:00
Guid: entryUrl,
Title: entry.Title(),
Link: entryUrl,
PubDate: entry.PublishedAt().Format(time.RFC1123Z),
Description: RSSDescription{
Text: string(content),
},
2023-07-20 17:49:52 +00:00
})
}
buf := new(bytes.Buffer)
2023-07-21 19:40:32 +00:00
encoder := xml.NewEncoder(buf)
encoder.Indent("", " ")
err := encoder.Encode(rss)
2023-07-20 17:49:52 +00:00
if err != nil {
return "", err
}
return xml.Header + buf.String(), nil
}
2023-06-25 19:32:36 +00:00
type RSSHandler struct {
siteConfigService *app.SiteConfigService
entrySvc *app.EntryService
2023-06-25 19:32:36 +00:00
}
func NewRSSHandler(entryService *app.EntryService, siteConfigService *app.SiteConfigService) *RSSHandler {
return &RSSHandler{entrySvc: entryService, siteConfigService: siteConfigService}
2023-06-25 19:32:36 +00:00
}
func (h *RSSHandler) Handle(c *fiber.Ctx) error {
2023-07-20 17:49:52 +00:00
c.Set(fiber.HeaderContentType, fiber.MIMEApplicationXML)
siteConfig, err := h.siteConfigService.GetSiteConfig()
if err != nil {
return err
}
2023-07-20 17:49:52 +00:00
entries, err := h.entrySvc.FindAllByType(&siteConfig.PrimaryListInclude, true, false)
if err != nil {
return err
}
// sort entries by date descending
sort.Slice(entries, func(i, j int) bool {
return entries[i].PublishedAt().After(*entries[j].PublishedAt())
})
rss, err := RenderRSSFeed(siteConfig, entries)
if err != nil {
return err
}
return c.SendString(rss)
2023-06-25 19:32:36 +00:00
}