diff --git a/core/admin.go b/core/admin.go index 0e9dfa4..feda5c9 100644 --- a/core/admin.go +++ b/core/admin.go @@ -185,6 +185,7 @@ func (b *Blog) SettingsHandler(w http.ResponseWriter, r *http.Request) { mailPort, _ := strconv.Atoi(r.FormValue("mail-port")) form := &forms.Settings{ Title: r.FormValue("title"), + Description: r.FormValue("description"), AdminEmail: r.FormValue("admin-email"), URL: r.FormValue("url"), 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 // any validation errors. settings.Site.Title = form.Title + settings.Site.Description = form.Description settings.Site.AdminEmail = form.AdminEmail settings.Site.URL = form.URL settings.Redis.Enabled = form.RedisEnabled diff --git a/core/blog.go b/core/blog.go index 16b291b..c52be92 100644 --- a/core/blog.go +++ b/core/blog.go @@ -11,9 +11,11 @@ import ( "strings" "time" + "github.com/gorilla/feeds" "github.com/gorilla/mux" "github.com/kirsle/blog/core/models/comments" "github.com/kirsle/blog/core/models/posts" + "github.com/kirsle/blog/core/models/settings" "github.com/kirsle/blog/core/models/users" "github.com/urfave/negroni" ) @@ -39,6 +41,8 @@ type Archive struct { func (b *Blog) BlogRoutes(r *mux.Router) { // Public routes r.HandleFunc("/blog", b.IndexHandler) + r.HandleFunc("/blog.rss", b.RSSHandler) + r.HandleFunc("/blog.atom", b.RSSHandler) r.HandleFunc("/archive", b.BlogArchive) r.HandleFunc("/tagged", 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, "")[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. func (b *Blog) IndexHandler(w http.ResponseWriter, r *http.Request) { 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. -func (b *Blog) RenderIndex(r *http.Request, tag, privacy string) template.HTML { +// RecentPosts gets and filters the blog entries and orders them by most recent. +func (b *Blog) RecentPosts(r *http.Request, tag, privacy string) []posts.Post { // Get the blog index. idx, _ := posts.GetIndex() @@ -182,12 +231,18 @@ func (b *Blog) RenderIndex(r *http.Request, tag, privacy string) template.HTML { 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 { return template.HTML("No blog posts were found.") } - sort.Sort(sort.Reverse(posts.ByUpdated(pool))) - // Query parameters. page, _ := strconv.Atoi(r.URL.Query().Get("page")) if page <= 0 { diff --git a/core/forms/settings.go b/core/forms/settings.go index 0caefba..f49d9f4 100644 --- a/core/forms/settings.go +++ b/core/forms/settings.go @@ -8,6 +8,7 @@ import ( // Settings are the user-facing admin settings. type Settings struct { Title string + Description string AdminEmail string URL string RedisEnabled bool diff --git a/core/models/settings/settings.go b/core/models/settings/settings.go index e5a7b92..d933ffd 100644 --- a/core/models/settings/settings.go +++ b/core/models/settings/settings.go @@ -17,9 +17,10 @@ type Settings struct { Initialized bool `json:"initialized"` Site struct { - Title string `json:"title"` - AdminEmail string `json:"adminEmail"` - URL string `json:"url"` + Title string `json:"title"` + Description string `json:"description"` + AdminEmail string `json:"adminEmail"` + URL string `json:"url"` } `json:"site"` // Security-related settings. diff --git a/root/admin/settings.gohtml b/root/admin/settings.gohtml index 7c36c7a..9a7e951 100644 --- a/root/admin/settings.gohtml +++ b/root/admin/settings.gohtml @@ -15,6 +15,15 @@ placeholder="Website Title"> +
+ + +
+
For getting notifications about comments, etc.