Bring back the RSS/Atom feeds

pull/4/head
Noah 2018-02-01 20:14:42 -08:00
parent 9f25d38276
commit 0ca2ebd874
5 changed files with 75 additions and 7 deletions

View File

@ -185,6 +185,7 @@ func (b *Blog) SettingsHandler(w http.ResponseWriter, r *http.Request) {
mailPort, _ := strconv.Atoi(r.FormValue("mail-port")) mailPort, _ := strconv.Atoi(r.FormValue("mail-port"))
form := &forms.Settings{ form := &forms.Settings{
Title: r.FormValue("title"), Title: r.FormValue("title"),
Description: r.FormValue("description"),
AdminEmail: r.FormValue("admin-email"), AdminEmail: r.FormValue("admin-email"),
URL: r.FormValue("url"), URL: r.FormValue("url"),
RedisEnabled: len(r.FormValue("redis-enabled")) > 0, RedisEnabled: len(r.FormValue("redis-enabled")) > 0,
@ -203,6 +204,7 @@ func (b *Blog) SettingsHandler(w http.ResponseWriter, r *http.Request) {
// Copy form values into the settings struct for display, in case of // Copy form values into the settings struct for display, in case of
// any validation errors. // any validation errors.
settings.Site.Title = form.Title settings.Site.Title = form.Title
settings.Site.Description = form.Description
settings.Site.AdminEmail = form.AdminEmail settings.Site.AdminEmail = form.AdminEmail
settings.Site.URL = form.URL settings.Site.URL = form.URL
settings.Redis.Enabled = form.RedisEnabled settings.Redis.Enabled = form.RedisEnabled

View File

@ -11,9 +11,11 @@ import (
"strings" "strings"
"time" "time"
"github.com/gorilla/feeds"
"github.com/gorilla/mux" "github.com/gorilla/mux"
"github.com/kirsle/blog/core/models/comments" "github.com/kirsle/blog/core/models/comments"
"github.com/kirsle/blog/core/models/posts" "github.com/kirsle/blog/core/models/posts"
"github.com/kirsle/blog/core/models/settings"
"github.com/kirsle/blog/core/models/users" "github.com/kirsle/blog/core/models/users"
"github.com/urfave/negroni" "github.com/urfave/negroni"
) )
@ -39,6 +41,8 @@ type Archive struct {
func (b *Blog) BlogRoutes(r *mux.Router) { func (b *Blog) BlogRoutes(r *mux.Router) {
// Public routes // Public routes
r.HandleFunc("/blog", b.IndexHandler) r.HandleFunc("/blog", b.IndexHandler)
r.HandleFunc("/blog.rss", b.RSSHandler)
r.HandleFunc("/blog.atom", b.RSSHandler)
r.HandleFunc("/archive", b.BlogArchive) r.HandleFunc("/archive", b.BlogArchive)
r.HandleFunc("/tagged", b.Tagged) r.HandleFunc("/tagged", b.Tagged)
r.HandleFunc("/tagged/{tag}", b.Tagged) r.HandleFunc("/tagged/{tag}", b.Tagged)
@ -84,6 +88,51 @@ func (b *Blog) BlogRoutes(r *mux.Router) {
)) ))
} }
// RSSHandler renders an RSS feed from the blog.
func (b *Blog) RSSHandler(w http.ResponseWriter, r *http.Request) {
config, _ := settings.Load()
admin, err := users.Load(1)
if err != nil {
b.Error(w, r, "Blog isn't ready yet.")
return
}
feed := &feeds.Feed{
Title: config.Site.Title,
Link: &feeds.Link{Href: config.Site.URL},
Description: config.Site.Description,
Author: &feeds.Author{
Name: admin.Name,
Email: admin.Email,
},
Created: time.Now(),
}
feed.Items = []*feeds.Item{}
for i, p := range b.RecentPosts(r, "", "") {
feed.Items = append(feed.Items, &feeds.Item{
Title: p.Title,
Link: &feeds.Link{Href: config.Site.URL + p.Fragment},
Description: strings.Split(p.Body, "<snip>")[0],
Created: p.Created,
})
if i >= 5 {
break
}
}
// What format to encode it in?
if strings.Contains(r.URL.Path, ".atom") {
atom, _ := feed.ToAtom()
w.Header().Set("Content-Type", "application/atom+xml")
w.Write([]byte(atom))
} else {
rss, _ := feed.ToRss()
w.Header().Set("Content-Type", "application/rss+xml")
w.Write([]byte(rss))
}
}
// IndexHandler renders the main index page of the blog. // IndexHandler renders the main index page of the blog.
func (b *Blog) IndexHandler(w http.ResponseWriter, r *http.Request) { func (b *Blog) IndexHandler(w http.ResponseWriter, r *http.Request) {
b.CommonIndexHandler(w, r, "", "") b.CommonIndexHandler(w, r, "", "")
@ -133,8 +182,8 @@ func (b *Blog) CommonIndexHandler(w http.ResponseWriter, r *http.Request, tag, p
})) }))
} }
// RenderIndex renders and returns the blog index partial. // RecentPosts gets and filters the blog entries and orders them by most recent.
func (b *Blog) RenderIndex(r *http.Request, tag, privacy string) template.HTML { func (b *Blog) RecentPosts(r *http.Request, tag, privacy string) []posts.Post {
// Get the blog index. // Get the blog index.
idx, _ := posts.GetIndex() idx, _ := posts.GetIndex()
@ -182,12 +231,18 @@ func (b *Blog) RenderIndex(r *http.Request, tag, privacy string) template.HTML {
pool = append(pool, post) pool = append(pool, post)
} }
sort.Sort(sort.Reverse(posts.ByUpdated(pool)))
return pool
}
// RenderIndex renders and returns the blog index partial.
func (b *Blog) RenderIndex(r *http.Request, tag, privacy string) template.HTML {
// Get the recent blog entries, filtered by the tag/privacy settings.
pool := b.RecentPosts(r, tag, privacy)
if len(pool) == 0 { if len(pool) == 0 {
return template.HTML("No blog posts were found.") return template.HTML("No blog posts were found.")
} }
sort.Sort(sort.Reverse(posts.ByUpdated(pool)))
// Query parameters. // Query parameters.
page, _ := strconv.Atoi(r.URL.Query().Get("page")) page, _ := strconv.Atoi(r.URL.Query().Get("page"))
if page <= 0 { if page <= 0 {

View File

@ -8,6 +8,7 @@ import (
// Settings are the user-facing admin settings. // Settings are the user-facing admin settings.
type Settings struct { type Settings struct {
Title string Title string
Description string
AdminEmail string AdminEmail string
URL string URL string
RedisEnabled bool RedisEnabled bool

View File

@ -17,9 +17,10 @@ type Settings struct {
Initialized bool `json:"initialized"` Initialized bool `json:"initialized"`
Site struct { Site struct {
Title string `json:"title"` Title string `json:"title"`
AdminEmail string `json:"adminEmail"` Description string `json:"description"`
URL string `json:"url"` AdminEmail string `json:"adminEmail"`
URL string `json:"url"`
} `json:"site"` } `json:"site"`
// Security-related settings. // Security-related settings.

View File

@ -15,6 +15,15 @@
placeholder="Website Title"> placeholder="Website Title">
</div> </div>
<div class="form-group">
<label for="title">Description</label>
<input type="text"
class="form-control"
name="description"
value="{{ .Site.Description }}"
placeholder="Just another web blog.">
</div>
<div class="form-group"> <div class="form-group">
<label for="admin-email">Admin Email</label> <label for="admin-email">Admin Email</label>
<small class="text-muted">For getting notifications about comments, etc.</small> <small class="text-muted">For getting notifications about comments, etc.</small>