apps/easel/feed.go 2.8 K raw
1
package main
2
3
import (
4
	"net/http"
5
	"strings"
6
	"time"
7
)
8
9
func entryPublished(date string) string {
10
	if d, err := time.Parse("2006-01-02", date); err == nil {
11
		return time.Date(d.Year(), d.Month(), d.Day(), 12, 0, 0, 0, time.UTC).Format(time.RFC3339)
12
	}
13
	return time.Now().UTC().Format(time.RFC3339)
14
}
15
16
func escapeXML(s string) string {
17
	r := strings.NewReplacer(
18
		"&", "&",
19
		"<", "&lt;",
20
		">", "&gt;",
21
		`"`, "&quot;",
22
		"'", "&apos;",
23
	)
24
	return r.Replace(s)
25
}
26
27
func (a *App) atomFeedHandler(w http.ResponseWriter, r *http.Request) {
28
	items, err := listDaily(a.DB, 100)
29
	if err != nil {
30
		a.Log.Error("atom feed query failed", "err", err)
31
		w.WriteHeader(http.StatusInternalServerError)
32
		return
33
	}
34
	updated := time.Now().UTC().Format(time.RFC3339)
35
	if len(items) > 0 {
36
		updated = entryPublished(items[0].Date)
37
	}
38
	base := strings.TrimRight(a.BaseURL, "/")
39
	selfURL := base + "/feed.xml"
40
41
	var b strings.Builder
42
	b.WriteString("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
43
	b.WriteString("<feed xmlns=\"http://www.w3.org/2005/Atom\">\n")
44
	b.WriteString("  <title>Easel — Daily Artwork</title>\n")
45
	b.WriteString("  <subtitle>A daily painting from the Art Institute of Chicago</subtitle>\n")
46
	b.WriteString(`  <link href="` + escapeXML(selfURL) + `" rel="self" type="application/atom+xml" />` + "\n")
47
	b.WriteString(`  <link href="` + escapeXML(base) + `" />` + "\n")
48
	b.WriteString("  <id>" + escapeXML(selfURL) + "</id>\n")
49
	b.WriteString("  <updated>" + updated + "</updated>\n")
50
51
	for _, item := range items {
52
		published := entryPublished(item.Date)
53
		entryURL := base + "/day/" + item.Date
54
		author := item.ArtistTitle.String
55
		if author == "" {
56
			author = item.ArtistDisplay.String
57
		}
58
		if author == "" {
59
			author = "Unknown"
60
		}
61
		summary := item.ShortDescription.String
62
		if summary == "" {
63
			summary = item.Description.String
64
		}
65
		image := iiifURL(item.ImageID)
66
		content := `<p><img src="` + escapeXML(image) + `" alt="` + escapeXML(item.Title) + `" /></p><p>` + escapeXML(summary) + `</p>`
67
68
		b.WriteString("  <entry>\n")
69
		b.WriteString("    <title>" + escapeXML(item.Date) + " — " + escapeXML(item.Title) + "</title>\n")
70
		b.WriteString(`    <link href="` + escapeXML(entryURL) + `" />` + "\n")
71
		b.WriteString("    <id>" + escapeXML(entryURL) + "</id>\n")
72
		b.WriteString("    <updated>" + published + "</updated>\n")
73
		b.WriteString("    <published>" + published + "</published>\n")
74
		b.WriteString("    <author>\n")
75
		b.WriteString("      <name>" + escapeXML(author) + "</name>\n")
76
		b.WriteString("    </author>\n")
77
		if summary != "" {
78
			b.WriteString("    <summary>" + escapeXML(summary) + "</summary>\n")
79
		}
80
		b.WriteString(`    <content type="html">` + escapeXML(content) + `</content>` + "\n")
81
		b.WriteString("  </entry>\n")
82
	}
83
	b.WriteString("</feed>\n")
84
85
	w.Header().Set("Content-Type", "application/atom+xml; charset=utf-8")
86
	_, _ = w.Write([]byte(b.String()))
87
}