mirror of https://github.com/jlelse/GoBlog
Add RSS/Atom/JSON Feed
parent
4cc33c91db
commit
341d9ab3f5
|
@ -0,0 +1,59 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/gorilla/feeds"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
type feedType string
|
||||
|
||||
const (
|
||||
RSS feedType = "rss"
|
||||
ATOM feedType = "atom"
|
||||
JSON feedType = "json"
|
||||
)
|
||||
|
||||
func generateFeed(f feedType, w http.ResponseWriter, posts []*Post, title string, description string) {
|
||||
now := time.Now()
|
||||
feed := &feeds.Feed{
|
||||
Title: title,
|
||||
Description: description,
|
||||
Link: &feeds.Link{},
|
||||
Created: now,
|
||||
}
|
||||
for _, postItem := range posts {
|
||||
htmlContent, _ := renderMarkdown(postItem.Content)
|
||||
feed.Add(&feeds.Item{
|
||||
Title: postItem.title(),
|
||||
Link: &feeds.Link{Href: postItem.Path},
|
||||
Description: string(htmlContent),
|
||||
Id: postItem.Path,
|
||||
Content: string(htmlContent),
|
||||
})
|
||||
}
|
||||
var feedStr string
|
||||
var err error
|
||||
switch f {
|
||||
case RSS:
|
||||
feedStr, err = feed.ToRss()
|
||||
case ATOM:
|
||||
feedStr, err = feed.ToAtom()
|
||||
case JSON:
|
||||
feedStr, err = feed.ToJSON()
|
||||
}
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
switch f {
|
||||
case RSS:
|
||||
w.Header().Add("Content-Type", "application/rss+xml; charset=utf-8")
|
||||
case ATOM:
|
||||
w.Header().Add("Content-Type", "application/atom+xml; charset=utf-8")
|
||||
case JSON:
|
||||
w.Header().Add("Content-Type", "application/feed+json; charset=utf-8")
|
||||
}
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_, _ = w.Write([]byte(feedStr))
|
||||
}
|
6
go.mod
6
go.mod
|
@ -9,8 +9,10 @@ require (
|
|||
github.com/go-chi/chi v4.1.2+incompatible
|
||||
github.com/google/go-cmp v0.5.2 // indirect
|
||||
github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 // indirect
|
||||
github.com/gorilla/feeds v1.1.1
|
||||
github.com/jinzhu/gorm v1.9.16 // indirect
|
||||
github.com/klauspost/cpuid v1.3.1 // indirect
|
||||
github.com/kr/pretty v0.2.1 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/kyokomi/emoji v2.2.4+incompatible
|
||||
github.com/lib/pq v1.8.0 // indirect
|
||||
|
@ -26,7 +28,7 @@ require (
|
|||
github.com/spf13/cast v1.3.1 // indirect
|
||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||
github.com/spf13/viper v1.7.1
|
||||
github.com/tdewolff/minify/v2 v2.9.2
|
||||
github.com/tdewolff/minify/v2 v2.9.3
|
||||
github.com/vcraescu/go-paginator v0.0.0-20200304054438-86d84f27c0b3
|
||||
github.com/yuin/goldmark v1.2.1
|
||||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a // indirect
|
||||
|
@ -34,7 +36,7 @@ require (
|
|||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 // indirect
|
||||
golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a // indirect
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect
|
||||
gopkg.in/ini.v1 v1.60.2 // indirect
|
||||
gopkg.in/square/go-jose.v2 v2.5.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 // indirect
|
||||
|
|
12
go.sum
12
go.sum
|
@ -183,6 +183,8 @@ github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORR
|
|||
github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 h1:l5lAOZEym3oK3SQ2HBHWsJUfbNBiTXJDeW2QDxw9AQ0=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||
github.com/gorilla/feeds v1.1.1 h1:HwKXxqzcRNg9to+BbvJog4+f3s/xzvtZXICcQGutYfY=
|
||||
github.com/gorilla/feeds v1.1.1/go.mod h1:Nk0jZrvPFZX1OBe5NPiddPw7CfwF6Q9eqzaBbaightA=
|
||||
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
|
@ -251,6 +253,8 @@ github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
|||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
|
@ -412,8 +416,8 @@ github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd
|
|||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/tdewolff/minify/v2 v2.9.2 h1:paeFMZEtrmWVJSmvZ+htMQ5RhbkBbLVyXdzs6f8Es+s=
|
||||
github.com/tdewolff/minify/v2 v2.9.2/go.mod h1:njYNbXhVTAhI1hARVHCbHAgRd44j+AEt0LdW+menKsY=
|
||||
github.com/tdewolff/minify/v2 v2.9.3 h1:5RMoa8DAqfI/Gne9rM1hnsQXZax24dnZhcQWHOFD7f4=
|
||||
github.com/tdewolff/minify/v2 v2.9.3/go.mod h1:njYNbXhVTAhI1hARVHCbHAgRd44j+AEt0LdW+menKsY=
|
||||
github.com/tdewolff/parse/v2 v2.5.1 h1:1PxbcgMxb8RWH1nmeQjBC+lZIOTUEjiYQ3u8RpzndN0=
|
||||
github.com/tdewolff/parse/v2 v2.5.1/go.mod h1:WzaJpRSbwq++EIQHYIRTpbYKNA3gn9it1Ik++q4zyho=
|
||||
github.com/tdewolff/test v1.0.6 h1:76mzYJQ83Op284kMT+63iCNCI7NEERsIN8dLM+RiKr4=
|
||||
|
@ -682,8 +686,8 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
|
|||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U=
|
||||
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/h2non/gock.v1 v1.0.15/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdODlynE=
|
||||
|
|
3
http.go
3
http.go
|
@ -110,10 +110,9 @@ func buildHandler() (http.Handler, error) {
|
|||
}
|
||||
}
|
||||
|
||||
routePatterns := routesToStringSlice(r.Routes())
|
||||
rootPath := "/"
|
||||
blogPath := "/blog"
|
||||
if !routePatterns.has(rootPath) {
|
||||
if routePatterns := routesToStringSlice(r.Routes()); !routePatterns.has(rootPath) {
|
||||
r.With(cacheMiddleware, minifier.Middleware).Get(rootPath, serveHome(rootPath))
|
||||
r.With(cacheMiddleware, minifier.Middleware).Get(paginationPath, serveHome(rootPath))
|
||||
} else if !routePatterns.has(blogPath) {
|
||||
|
|
|
@ -5,7 +5,8 @@ import (
|
|||
"github.com/tdewolff/minify/v2/css"
|
||||
"github.com/tdewolff/minify/v2/html"
|
||||
"github.com/tdewolff/minify/v2/js"
|
||||
"regexp"
|
||||
"github.com/tdewolff/minify/v2/json"
|
||||
"github.com/tdewolff/minify/v2/xml"
|
||||
)
|
||||
|
||||
var minifier *minify.M
|
||||
|
@ -14,5 +15,8 @@ func initMinify() {
|
|||
minifier = minify.New()
|
||||
minifier.AddFunc("text/html", html.Minify)
|
||||
minifier.AddFunc("text/css", css.Minify)
|
||||
minifier.AddFuncRegexp(regexp.MustCompile("^(application|text)/(x-)?(java|ecma)script$"), js.Minify)
|
||||
minifier.AddFunc("application/javascript", js.Minify)
|
||||
minifier.AddFunc("application/rss+xml", xml.Minify)
|
||||
minifier.AddFunc("application/atom+xml", xml.Minify)
|
||||
minifier.AddFunc("application/feed+json", json.Minify)
|
||||
}
|
||||
|
|
16
posts.go
16
posts.go
|
@ -23,6 +23,17 @@ type Post struct {
|
|||
Parameters map[string][]string `json:"parameters"`
|
||||
}
|
||||
|
||||
func (p *Post) firstParameter(parameter string) (result string) {
|
||||
if pp := p.Parameters[parameter]; len(pp) > 0 {
|
||||
result = pp[0]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (p *Post) title() string {
|
||||
return p.firstParameter("title")
|
||||
}
|
||||
|
||||
func servePost(w http.ResponseWriter, r *http.Request) {
|
||||
path := slashTrimmedPath(r)
|
||||
post, err := getPost(r.Context(), path)
|
||||
|
@ -140,6 +151,11 @@ func serveIndex(path string, sec *section, tax *taxonomy, taxonomyValue string)
|
|||
title = appConfig.Blog.Title
|
||||
description = appConfig.Blog.Description
|
||||
}
|
||||
f := feedType(r.URL.Query().Get("feed"))
|
||||
if f != "" {
|
||||
generateFeed(f, w, posts, title, description)
|
||||
return
|
||||
}
|
||||
render(w, templateIndex, &indexTemplateData{
|
||||
Title: title,
|
||||
Description: description,
|
||||
|
|
13
render.go
13
render.go
|
@ -32,17 +32,16 @@ func initRendering() {
|
|||
return template.HTML(htmlContent)
|
||||
},
|
||||
// First parameter value
|
||||
"p": func(post Post, parameter string) string {
|
||||
if len(post.Parameters[parameter]) > 0 {
|
||||
return post.Parameters[parameter][0]
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
"p": func(post *Post, parameter string) string {
|
||||
return post.firstParameter(parameter)
|
||||
},
|
||||
// All parameter values
|
||||
"ps": func(post Post, parameter string) []string {
|
||||
"ps": func(post *Post, parameter string) []string {
|
||||
return post.Parameters[parameter]
|
||||
},
|
||||
"title": func(post *Post) string {
|
||||
return post.title()
|
||||
},
|
||||
"include": func(templateName string, data interface{}) (template.HTML, error) {
|
||||
buf := new(bytes.Buffer)
|
||||
err := templates[templateName].ExecuteTemplate(buf, templateName, data)
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
{{ define "main" }}
|
||||
<main class=h-entry>
|
||||
<article>
|
||||
{{ with p . "title" }}<h1 class=p-name>{{ . }}</h1>{{ end }}
|
||||
{{ with title . }}<h1 class=p-name>{{ . }}</h1>{{ end }}
|
||||
{{ with .Content }}
|
||||
<div class=e-content>{{ md . }}</div>
|
||||
{{ end }}
|
||||
|
|
Loading…
Reference in New Issue