package handler import ( "fmt" "net/http" "status/model" "time" ) import ( "encoding/xml" ) type Feed struct { XMLName xml.Name `xml:"http://www.w3.org/2005/Atom feed"` Title string `xml:"title"` ID string `xml:"id"` Link []Link `xml:"link"` Updated TimeStr `xml:"updated"` Author *Person `xml:"author"` Icon string `xml:"icon,omitempty"` Logo string `xml:"logo,omitempty"` Subtitle string `xml:"subtitle,omitempty"` Entry []*Entry `xml:"entry"` } type Entry struct { Title string `xml:"title"` ID string `xml:"id"` Link []Link `xml:"link"` Published TimeStr `xml:"published"` Updated TimeStr `xml:"updated"` Author *Person `xml:"author"` Summary *Text `xml:"summary"` Content *Text `xml:"content"` } type Link struct { Rel string `xml:"rel,attr,omitempty"` Href string `xml:"href,attr"` Type string `xml:"type,attr,omitempty"` HrefLang string `xml:"hreflang,attr,omitempty"` Title string `xml:"title,attr,omitempty"` Length uint `xml:"length,attr,omitempty"` } type Person struct { Name string `xml:"name"` URI string `xml:"uri,omitempty"` Email string `xml:"email,omitempty"` InnerXML string `xml:",innerxml"` } type Text struct { Type string `xml:"type,attr"` Body string `xml:",chardata"` } type TimeStr string func Time(t time.Time) TimeStr { return TimeStr(t.Format("2006-01-02T15:04:05-07:00")) } func createAtomEntryFromStatus(status model.Status) *Entry { return &Entry{ Title: fmt.Sprintf("%s %s %s", status.User, status.Face, truncate(status.Content, 50)), ID: fmt.Sprintf("https://status.cafe/users/%s/%d", status.User, status.Id), Link: []Link{ { Rel: "alternate", Href: fmt.Sprintf("https://status.cafe/users/%s", status.User), Type: "text/html", }, }, Updated: Time(status.CreatedAt), Published: Time(status.CreatedAt), Author: &Person{ Name: status.User, URI: fmt.Sprintf("https://status.cafe/users/%s", status.User), }, Content: &Text{ Type: "html", Body: status.ContentDisplay(), }, } } func (h *Handler) showFeedView(w http.ResponseWriter, r *http.Request) { feed := Feed{ Title: "status.cafe", ID: "https://status.cafe/", Subtitle: "Your friends' updates", Icon: "/assets/icon.png", Author: &Person{ Name: "status.cafe", URI: "https://status.cafe", }, Updated: Time(time.Now()), Link: []Link{ { Rel: "self", Href: "https://status.cafe/feed.atom", }, { Rel: "alternate", Type: "text/html", Href: "https://status.cafe", }, }, } statuses, err := h.storage.StatusFeed() if err != nil { serverError(w, err) return } for _, status := range statuses { feed.Entry = append(feed.Entry, createAtomEntryFromStatus(status)) } w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Content-Type", "application/atom+xml") var data []byte data, err = xml.MarshalIndent(&feed, "", " ") if err != nil { serverError(w, err) } w.Write([]byte(xml.Header + string(data))) }