beebo
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

add /feeds/{feed} endpoint, show feed failures to user

+58 -18
+21
files/feedDetails.tmpl.html
··· 1 + {{ define "feedDetails" }} 2 + {{ template "head" . }} 3 + {{ template "nav" . }} 4 + <h3>{{ .Data.Feed.UpdateURL }}</h3> 5 + <p> 6 + Title: {{ .Data.Feed.Title }} 7 + Description: {{ .Data.Feed.Description }} 8 + Next Refresh: {{ .Data.Feed.Refresh }} 9 + Last Fetch Failure: {{ .Data.FetchFailure }} 10 + </p> 11 + {{ len .Data.Feed.Items }} Items:</p> 12 + {{ range .Data.Feed.Items }} 13 + <details> 14 + <summary>{{ .Title }}</summary> 15 + <p>Date: {{ .Date }} 16 + Link: <a href="{{ .Link }}">{{ .Link }}</a> 17 + </p> 18 + </details> 19 + {{ end }} 20 + {{ template "tail" . }} 21 + {{ end }}
+5 -18
files/settings.tmpl.html
··· 48 48 ( づ♡ 49 49 </p> 50 50 {{ else if gt $length 0 }} 51 - <p>feed details:</p> 51 + <p>feed details 👁️👄👁️</p> 52 52 {{ end }} 53 - {{ range .Data }} 54 - <details> 55 - <summary>{{ .UpdateURL }}</summary> 56 - <p>Title: {{ .Title | trimSpace }} 57 - Description: "{{ .Description | trimSpace }}" 58 - Refresh: {{ .Refresh.Format "Jan 02, 15:04:05 UTC" }} 59 - {{ len .Items }} Items:</p> 60 - {{ range .Items }} 61 - <details> 62 - <summary>{{ .Title }}</summary> 63 - <p>Date: {{ .Date }} 64 - Link: {{ .Link }} 53 + <p> 54 + {{ range .Data -}} 55 + <a href="/feeds/{{ .UpdateURL | escapeURL }}">{{ .UpdateURL }}</a> 56 + {{ end -}} 65 57 </p> 66 - </details> 67 - {{ end }} 68 - </p> 69 - </details> 70 - {{ end }} 71 58 {{ template "tail" . }} 72 59 {{ end }}
+1
main.go
··· 22 22 mux.HandleFunc("GET /logout", s.logoutHandler) 23 23 mux.HandleFunc("POST /logout", s.logoutHandler) 24 24 mux.HandleFunc("POST /register", s.registerHandler) 25 + mux.HandleFunc("GET /feeds/{url}", s.feedDetailsHandler) 25 26 26 27 // left in-place for backwards compat 27 28 mux.HandleFunc("GET /feeds", s.settingsHandler)
+4
reaper/reaper.go
··· 102 102 return false 103 103 } 104 104 105 + func (r *Reaper) GetFeed(url string) *rss.Feed { 106 + return r.feeds[url] 107 + } 108 + 105 109 // GetUserFeeds returns a list of feeds 106 110 func (r *Reaper) GetUserFeeds(username string) []*rss.Feed { 107 111 urls := r.db.GetUserFeedURLs(username)
+27
site.go
··· 197 197 http.Redirect(w, r, "/settings", http.StatusSeeOther) 198 198 } 199 199 200 + func (s *Site) feedDetailsHandler(w http.ResponseWriter, r *http.Request) { 201 + encodedURL := muxpatterns.PathValue(r, "url") 202 + decodedURL, err := url.QueryUnescape(encodedURL) 203 + if err != nil { 204 + e := fmt.Sprintf("failed to decode URL '%s' %s", encodedURL, err) 205 + s.renderErr(w, e, http.StatusBadRequest) 206 + return 207 + } 208 + fetchErr, err := s.db.GetFeedFetchError(decodedURL) 209 + if err != nil { 210 + e := fmt.Sprintf("failed to fetch feed error '%s' %s", encodedURL, err) 211 + s.renderErr(w, e, http.StatusBadRequest) 212 + return 213 + } 214 + 215 + feedData := struct { 216 + Feed *rss.Feed 217 + FetchFailure string 218 + }{ 219 + Feed: s.reaper.GetFeed(decodedURL), 220 + FetchFailure: fetchErr, 221 + } 222 + 223 + s.renderPage(w, r, "feedDetails", feedData) 224 + } 225 + 200 226 // username fetches a client's username based 201 227 // on the sessionToken that user has set. username 202 228 // will return "" if there is no sessionToken. ··· 279 305 "printDomain": s.printDomain, 280 306 "timeSince": s.timeSince, 281 307 "trimSpace": strings.TrimSpace, 308 + "escapeURL": url.QueryEscape, 282 309 } 283 310 284 311 tmplFiles := filepath.Join("files", "*.tmpl.html")