mirror of https://github.com/jlelse/GoBlog
Various improvements; Remove Hugo import API; Add feeds for photos
This commit is contained in:
parent
82ace66544
commit
99789efcd3
|
@ -84,8 +84,7 @@ func apHandleWebfinger(w http.ResponseWriter, r *http.Request) {
|
|||
serveError(w, r, "Blog not found", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
w.Header().Set(contentType, "application/jrd+json"+charsetUtf8Suffix)
|
||||
_ = json.NewEncoder(w).Encode(map[string]interface{}{
|
||||
b, _ := json.Marshal(map[string]interface{}{
|
||||
"subject": "acct:" + name + "@" + appConfig.Server.publicHostname,
|
||||
"links": []map[string]string{
|
||||
{
|
||||
|
@ -95,6 +94,8 @@ func apHandleWebfinger(w http.ResponseWriter, r *http.Request) {
|
|||
},
|
||||
},
|
||||
})
|
||||
w.Header().Set(contentType, "application/jrd+json"+charsetUtf8Suffix)
|
||||
_, _ = writeMinified(w, contentTypeJSON, b)
|
||||
}
|
||||
|
||||
func apHandleInbox(w http.ResponseWriter, r *http.Request) {
|
||||
|
|
|
@ -14,9 +14,11 @@ var asContext = []string{"https://www.w3.org/ns/activitystreams"}
|
|||
|
||||
func manipulateAsPath(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
if lowerAccept := strings.ToLower(r.Header.Get("Accept")); (strings.Contains(lowerAccept, contentTypeAS) || strings.Contains(lowerAccept, "application/ld+json")) && !strings.Contains(lowerAccept, contentTypeHTML) {
|
||||
// Is ActivityStream, add ".as" to differentiate cache and also trigger as function
|
||||
r.URL.Path += ".as"
|
||||
if ap := appConfig.ActivityPub; ap != nil && ap.Enabled {
|
||||
if lowerAccept := strings.ToLower(r.Header.Get("Accept")); (strings.Contains(lowerAccept, contentTypeAS) || strings.Contains(lowerAccept, "application/ld+json")) && !strings.Contains(lowerAccept, contentTypeHTML) {
|
||||
// Is ActivityStream, add ".as" to differentiate cache and also trigger as function
|
||||
r.URL.Path += ".as"
|
||||
}
|
||||
}
|
||||
next.ServeHTTP(rw, r)
|
||||
})
|
||||
|
@ -68,9 +70,9 @@ type asEndpoints struct {
|
|||
}
|
||||
|
||||
func (p *post) serveActivityStreams(w http.ResponseWriter) {
|
||||
// Send JSON
|
||||
w.Header().Add(contentType, contentTypeASUTF8)
|
||||
_ = json.NewEncoder(w).Encode(p.toASNote())
|
||||
b, _ := json.Marshal(p.toASNote())
|
||||
w.Header().Set(contentType, contentTypeASUTF8)
|
||||
_, _ = writeMinified(w, contentTypeAS, b)
|
||||
}
|
||||
|
||||
func (p *post) toASNote() *asNote {
|
||||
|
@ -126,8 +128,6 @@ func (b *configBlog) serveActivityStreams(blog string, w http.ResponseWriter, r
|
|||
serveError(w, r, "Failed to marshal public key", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
// Send JSON
|
||||
w.Header().Add(contentType, contentTypeASUTF8)
|
||||
asBlog := &asPerson{
|
||||
Context: asContext,
|
||||
Type: "Person",
|
||||
|
@ -154,5 +154,7 @@ func (b *configBlog) serveActivityStreams(blog string, w http.ResponseWriter, r
|
|||
URL: appConfig.User.Picture,
|
||||
}
|
||||
}
|
||||
_ = json.NewEncoder(w).Encode(asBlog)
|
||||
jb, _ := json.Marshal(asBlog)
|
||||
w.Header().Set(contentType, contentTypeASUTF8)
|
||||
_, _ = writeMinified(w, contentTypeAS, jb)
|
||||
}
|
||||
|
|
61
api.go
61
api.go
|
@ -1,61 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Not tested anymore
|
||||
|
||||
func apiPostCreateHugo(w http.ResponseWriter, r *http.Request) {
|
||||
blog := r.URL.Query().Get("blog")
|
||||
path := r.URL.Query().Get("path")
|
||||
section := r.URL.Query().Get("section")
|
||||
slug := r.URL.Query().Get("slug")
|
||||
alias := r.URL.Query().Get("alias")
|
||||
defer func() {
|
||||
_ = r.Body.Close()
|
||||
}()
|
||||
bodyContent, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
serveError(w, r, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
p, aliases, err := parseHugoFile(string(bodyContent))
|
||||
if err != nil {
|
||||
serveError(w, r, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
p.Blog = blog
|
||||
p.Path = path
|
||||
p.Section = section
|
||||
p.Slug = slug
|
||||
err = p.create()
|
||||
if err != nil {
|
||||
serveError(w, r, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
aliases = append(aliases, alias)
|
||||
for i, alias := range aliases {
|
||||
// Fix relativ paths
|
||||
if !strings.HasPrefix(alias, "/") {
|
||||
splittedPostPath := strings.Split(p.Path, "/")
|
||||
alias = strings.TrimSuffix(p.Path, splittedPostPath[len(splittedPostPath)-1]) + alias
|
||||
}
|
||||
alias = strings.TrimSuffix(alias, "/")
|
||||
if alias == p.Path {
|
||||
alias = ""
|
||||
}
|
||||
aliases[i] = alias
|
||||
}
|
||||
if len(aliases) > 0 {
|
||||
p.Parameters["aliases"] = aliases
|
||||
err = p.replace(p.Path, p.Status)
|
||||
if err != nil {
|
||||
serveError(w, r, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
}
|
||||
http.Redirect(w, r, p.fullURL(), http.StatusCreated)
|
||||
}
|
11
config.go
11
config.go
|
@ -16,7 +16,6 @@ type config struct {
|
|||
Blogs map[string]*configBlog `mapstructure:"blogs"`
|
||||
User *configUser `mapstructure:"user"`
|
||||
Hooks *configHooks `mapstructure:"hooks"`
|
||||
Hugo *configHugo `mapstructure:"hugo"`
|
||||
Micropub *configMicropub `mapstructure:"micropub"`
|
||||
PathRedirects []*configRegexRedirect `mapstructure:"pathRedirects"`
|
||||
ActivityPub *configActivityPub `mapstructure:"activityPub"`
|
||||
|
@ -151,15 +150,6 @@ type configHooks struct {
|
|||
PostDelete []string `mapstructure:"postdelete"`
|
||||
}
|
||||
|
||||
type configHugo struct {
|
||||
Frontmatter []*frontmatter `mapstructure:"frontmatter"`
|
||||
}
|
||||
|
||||
type frontmatter struct {
|
||||
Meta string `mapstructure:"meta"`
|
||||
Parameter string `mapstructure:"parameter"`
|
||||
}
|
||||
|
||||
type configMicropub struct {
|
||||
CategoryParam string `mapstructure:"categoryParam"`
|
||||
ReplyParam string `mapstructure:"replyParam"`
|
||||
|
@ -223,7 +213,6 @@ func initConfig() error {
|
|||
viper.SetDefault("user.nick", "admin")
|
||||
viper.SetDefault("user.password", "secret")
|
||||
viper.SetDefault("hooks.shell", "/bin/bash")
|
||||
viper.SetDefault("hugo.frontmatter", []*frontmatter{{Meta: "title", Parameter: "title"}, {Meta: "tags", Parameter: "tags"}})
|
||||
viper.SetDefault("micropub.categoryParam", "tags")
|
||||
viper.SetDefault("micropub.replyParam", "replylink")
|
||||
viper.SetDefault("micropub.likeParam", "likelink")
|
||||
|
|
|
@ -3,7 +3,7 @@ package main
|
|||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
|
@ -103,6 +103,6 @@ func editorMicropubPost(w http.ResponseWriter, r *http.Request, media bool) {
|
|||
return
|
||||
}
|
||||
w.WriteHeader(result.StatusCode)
|
||||
body, _ := ioutil.ReadAll(result.Body)
|
||||
_, _ = w.Write(body)
|
||||
_, _ = io.Copy(w, result.Body)
|
||||
_ = result.Body.Close()
|
||||
}
|
||||
|
|
15
feeds.go
15
feeds.go
|
@ -66,16 +66,17 @@ func generateFeed(blog string, f feedType, w http.ResponseWriter, r *http.Reques
|
|||
})
|
||||
}
|
||||
var err error
|
||||
var feedString, feedMediaType string
|
||||
switch f {
|
||||
case rssFeed:
|
||||
w.Header().Set(contentType, "application/rss+xml; charset=utf-8")
|
||||
err = feed.WriteRss(w)
|
||||
feedMediaType = contentTypeRSS
|
||||
feedString, err = feed.ToRss()
|
||||
case atomFeed:
|
||||
w.Header().Set(contentType, "application/atom+xml; charset=utf-8")
|
||||
err = feed.WriteAtom(w)
|
||||
feedMediaType = contentTypeATOM
|
||||
feedString, err = feed.ToAtom()
|
||||
case jsonFeed:
|
||||
w.Header().Set(contentType, "application/feed+json; charset=utf-8")
|
||||
err = feed.WriteJSON(w)
|
||||
feedMediaType = contentTypeJSONFeed
|
||||
feedString, err = feed.ToJSON()
|
||||
default:
|
||||
return
|
||||
}
|
||||
|
@ -84,4 +85,6 @@ func generateFeed(blog string, f feedType, w http.ResponseWriter, r *http.Reques
|
|||
serveError(w, r, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
w.Header().Set(contentType, feedMediaType+charsetUtf8Suffix)
|
||||
_, _ = writeMinified(w, feedMediaType, []byte(feedString))
|
||||
}
|
||||
|
|
4
go.mod
4
go.mod
|
@ -20,7 +20,6 @@ require (
|
|||
github.com/gorilla/feeds v1.1.1
|
||||
github.com/gorilla/handlers v1.5.1
|
||||
github.com/hashicorp/golang-lru v0.5.4
|
||||
github.com/jeremywohl/flatten v1.0.1
|
||||
github.com/jonboulle/clockwork v0.2.2 // indirect
|
||||
github.com/joncrlsn/dque v0.0.0-20200702023911-3e80e3146ce5
|
||||
github.com/klauspost/cpuid v1.3.1 // indirect
|
||||
|
@ -43,8 +42,7 @@ require (
|
|||
github.com/spf13/cast v1.3.1
|
||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||
github.com/spf13/viper v1.7.1
|
||||
github.com/tdewolff/minify/v2 v2.9.12
|
||||
github.com/tdewolff/parse/v2 v2.5.10 // indirect
|
||||
github.com/tdewolff/minify/v2 v2.9.13
|
||||
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80
|
||||
github.com/vcraescu/go-paginator v1.0.1-0.20201114172518-2cfc59fe05c2
|
||||
github.com/yuin/goldmark v1.3.2
|
||||
|
|
8
go.sum
8
go.sum
|
@ -142,8 +142,6 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO
|
|||
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
|
||||
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
|
||||
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
|
||||
github.com/jeremywohl/flatten v1.0.1 h1:LrsxmB3hfwJuE+ptGOijix1PIfOoKLJ3Uee/mzbgtrs=
|
||||
github.com/jeremywohl/flatten v1.0.1/go.mod h1:4AmD/VxjWcI5SRB0n6szE2A6s2fsNHDLO0nAlMHgfLQ=
|
||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
|
@ -284,10 +282,8 @@ github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5Cc
|
|||
github.com/stretchr/testify v1.7.0/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.12 h1:BKnbg3kcAuTLAhDeF3vSUxjvyj5lBRxaBvgxGCVLRRY=
|
||||
github.com/tdewolff/minify/v2 v2.9.12/go.mod h1:yuntVVAFuGyi9VmiRoUqAYEQnFCGO929ytj2ITMZuB8=
|
||||
github.com/tdewolff/parse/v2 v2.5.9 h1:9wCXRT3OcgYDNatgU+HUTOoGhE9WcnY5UxLNoJUe1yw=
|
||||
github.com/tdewolff/parse/v2 v2.5.9/go.mod h1:WzaJpRSbwq++EIQHYIRTpbYKNA3gn9it1Ik++q4zyho=
|
||||
github.com/tdewolff/minify/v2 v2.9.13 h1:RrwQhgGoYBhKN/ezStGB+crU64wPK1ZE5Jmkl63lif0=
|
||||
github.com/tdewolff/minify/v2 v2.9.13/go.mod h1:faNOp+awAoo+fhFHD+NAkBOaXBAvJI2X2SDERGKnARo=
|
||||
github.com/tdewolff/parse/v2 v2.5.10 h1:vj35n+ljq8LuYUx436s4qB18wuwP7thrLv+t1syE39M=
|
||||
github.com/tdewolff/parse/v2 v2.5.10/go.mod h1:WzaJpRSbwq++EIQHYIRTpbYKNA3gn9it1Ik++q4zyho=
|
||||
github.com/tdewolff/test v1.0.6 h1:76mzYJQ83Op284kMT+63iCNCI7NEERsIN8dLM+RiKr4=
|
||||
|
|
253
http.go
253
http.go
|
@ -23,6 +23,9 @@ const (
|
|||
contentTypeWWWForm = "application/x-www-form-urlencoded"
|
||||
contentTypeMultipartForm = "multipart/form-data"
|
||||
contentTypeAS = "application/activity+json"
|
||||
contentTypeRSS = "application/rss+xml"
|
||||
contentTypeATOM = "application/atom+xml"
|
||||
contentTypeJSONFeed = "application/feed+json"
|
||||
|
||||
contentTypeHTMLUTF8 = contentTypeHTML + charsetUtf8Suffix
|
||||
contentTypeJSONUTF8 = contentTypeJSON + charsetUtf8Suffix
|
||||
|
@ -99,15 +102,9 @@ func buildHandler() (http.Handler, error) {
|
|||
r.Mount("/debug", middleware.Profiler())
|
||||
}
|
||||
|
||||
// API
|
||||
r.Route("/api", func(apiRouter chi.Router) {
|
||||
apiRouter.Use(middleware.NoCache, authMiddleware)
|
||||
apiRouter.Post("/hugo", apiPostCreateHugo)
|
||||
})
|
||||
|
||||
// Micropub
|
||||
r.Route(micropubPath, func(mpRouter chi.Router) {
|
||||
mpRouter.Use(checkIndieAuth, middleware.NoCache, minifier.Middleware)
|
||||
mpRouter.Use(checkIndieAuth)
|
||||
mpRouter.Get("/", serveMicropubQuery)
|
||||
mpRouter.Post("/", serveMicropubPost)
|
||||
mpRouter.Post(micropubMediaSubPath, serveMicropubMedia)
|
||||
|
@ -115,7 +112,6 @@ func buildHandler() (http.Handler, error) {
|
|||
|
||||
// IndieAuth
|
||||
r.Route("/indieauth", func(indieauthRouter chi.Router) {
|
||||
indieauthRouter.Use(middleware.NoCache, minifier.Middleware)
|
||||
indieauthRouter.Get("/", indieAuthRequest)
|
||||
indieauthRouter.With(authMiddleware).Post("/accept", indieAuthAccept)
|
||||
indieauthRouter.Post("/", indieAuthVerification)
|
||||
|
@ -124,23 +120,26 @@ func buildHandler() (http.Handler, error) {
|
|||
})
|
||||
|
||||
// ActivityPub and stuff
|
||||
if appConfig.ActivityPub.Enabled {
|
||||
if ap := appConfig.ActivityPub; ap != nil && ap.Enabled {
|
||||
r.Post("/activitypub/inbox/{blog}", apHandleInbox)
|
||||
r.Post("/activitypub/{blog}/inbox", apHandleInbox)
|
||||
r.Get("/.well-known/webfinger", apHandleWebfinger)
|
||||
r.With(cacheMiddleware).Get("/.well-known/webfinger", apHandleWebfinger)
|
||||
r.With(cacheMiddleware).Get("/.well-known/host-meta", handleWellKnownHostMeta)
|
||||
r.With(cacheMiddleware, minifier.Middleware).Get("/.well-known/nodeinfo", serveNodeInfoDiscover)
|
||||
r.With(cacheMiddleware, minifier.Middleware).Get("/nodeinfo", serveNodeInfo)
|
||||
r.With(cacheMiddleware).Get("/.well-known/nodeinfo", serveNodeInfoDiscover)
|
||||
r.With(cacheMiddleware).Get("/nodeinfo", serveNodeInfo)
|
||||
}
|
||||
|
||||
// Webmentions
|
||||
r.Route(webmentionPath, func(webmentionRouter chi.Router) {
|
||||
webmentionRouter.Use(middleware.NoCache)
|
||||
webmentionRouter.Post("/", handleWebmention)
|
||||
webmentionRouter.With(minifier.Middleware, authMiddleware).Get("/", webmentionAdmin)
|
||||
webmentionRouter.With(minifier.Middleware, authMiddleware).Get(paginationPath, webmentionAdmin)
|
||||
webmentionRouter.With(authMiddleware).Post("/delete", webmentionAdminDelete)
|
||||
webmentionRouter.With(authMiddleware).Post("/approve", webmentionAdminApprove)
|
||||
webmentionRouter.Group(func(r chi.Router) {
|
||||
// Authenticated routes
|
||||
r.Use(authMiddleware)
|
||||
r.Get("/", webmentionAdmin)
|
||||
r.Get(paginationPath, webmentionAdmin)
|
||||
r.Post("/delete", webmentionAdminDelete)
|
||||
r.Post("/approve", webmentionAdminApprove)
|
||||
})
|
||||
})
|
||||
|
||||
// Posts
|
||||
|
@ -148,39 +147,36 @@ func buildHandler() (http.Handler, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var postMW []func(http.Handler) http.Handler
|
||||
if appConfig.ActivityPub.Enabled {
|
||||
postMW = []func(http.Handler) http.Handler{manipulateAsPath, cacheMiddleware, minifier.Middleware}
|
||||
} else {
|
||||
postMW = []func(http.Handler) http.Handler{cacheMiddleware, minifier.Middleware}
|
||||
}
|
||||
for _, path := range pp {
|
||||
if path != "" {
|
||||
r.With(postMW...).Get(path, servePost)
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Use(manipulateAsPath, cacheMiddleware)
|
||||
for _, path := range pp {
|
||||
r.Get(path, servePost)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Drafts
|
||||
dp, err := allPostPaths(statusDraft)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, path := range dp {
|
||||
if path != "" {
|
||||
r.With(middleware.NoCache, minifier.Middleware, authMiddleware).Get(path, servePost)
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Use(authMiddleware, cacheMiddleware)
|
||||
for _, path := range dp {
|
||||
r.Get(path, servePost)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Post aliases
|
||||
allPostAliases, err := allPostAliases()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, path := range allPostAliases {
|
||||
if path != "" {
|
||||
r.With(cacheMiddleware).Get(path, servePostAlias)
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Use(cacheMiddleware)
|
||||
for _, path := range allPostAliases {
|
||||
r.Get(path, servePostAlias)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Assets
|
||||
for _, path := range allAssetPaths() {
|
||||
|
@ -209,60 +205,79 @@ func buildHandler() (http.Handler, error) {
|
|||
blogPath = ""
|
||||
}
|
||||
|
||||
// Indexes, Feeds
|
||||
for _, section := range blogConfig.Sections {
|
||||
if section.Name != "" {
|
||||
path := blogPath + "/" + section.Name
|
||||
handler := serveSection(blog, path, section)
|
||||
r.With(cacheMiddleware, minifier.Middleware).Get(path, handler)
|
||||
r.With(cacheMiddleware, minifier.Middleware).Get(path+feedPath, handler)
|
||||
r.With(cacheMiddleware, minifier.Middleware).Get(path+paginationPath, handler)
|
||||
}
|
||||
}
|
||||
r.Group(func(r chi.Router) {
|
||||
|
||||
})
|
||||
|
||||
// Sections
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Use(cacheMiddleware)
|
||||
for _, section := range blogConfig.Sections {
|
||||
if section.Name != "" {
|
||||
secPath := blogPath + "/" + section.Name
|
||||
handler := serveSection(blog, secPath, section)
|
||||
r.Get(secPath, handler)
|
||||
r.Get(secPath+feedPath, handler)
|
||||
r.Get(secPath+paginationPath, handler)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Taxonomies
|
||||
for _, taxonomy := range blogConfig.Taxonomies {
|
||||
if taxonomy.Name != "" {
|
||||
path := blogPath + "/" + taxonomy.Name
|
||||
r.With(cacheMiddleware, minifier.Middleware).Get(path, serveTaxonomy(blog, taxonomy))
|
||||
values, err := allTaxonomyValues(blog, taxonomy.Name)
|
||||
taxPath := blogPath + "/" + taxonomy.Name
|
||||
taxValues, err := allTaxonomyValues(blog, taxonomy.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, tv := range values {
|
||||
vPath := path + "/" + urlize(tv)
|
||||
handler := serveTaxonomyValue(blog, vPath, taxonomy, tv)
|
||||
r.With(cacheMiddleware, minifier.Middleware).Get(vPath, handler)
|
||||
r.With(cacheMiddleware, minifier.Middleware).Get(vPath+feedPath, handler)
|
||||
r.With(cacheMiddleware, minifier.Middleware).Get(vPath+paginationPath, handler)
|
||||
}
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Use(cacheMiddleware)
|
||||
r.Get(taxPath, serveTaxonomy(blog, taxonomy))
|
||||
for _, tv := range taxValues {
|
||||
vPath := taxPath + "/" + urlize(tv)
|
||||
handler := serveTaxonomyValue(blog, vPath, taxonomy, tv)
|
||||
r.Get(vPath, handler)
|
||||
r.Get(vPath+feedPath, handler)
|
||||
r.Get(vPath+paginationPath, handler)
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Photos
|
||||
if blogConfig.Photos != nil && blogConfig.Photos.Enabled {
|
||||
photoPath := blogPath + blogConfig.Photos.Path
|
||||
handler := servePhotos(blog, photoPath)
|
||||
r.With(cacheMiddleware, minifier.Middleware).Get(photoPath, handler)
|
||||
r.With(cacheMiddleware, minifier.Middleware).Get(photoPath+paginationPath, handler)
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Use(cacheMiddleware)
|
||||
photoPath := blogPath + blogConfig.Photos.Path
|
||||
handler := servePhotos(blog, photoPath)
|
||||
r.Get(photoPath, handler)
|
||||
r.Get(photoPath+feedPath, handler)
|
||||
r.Get(photoPath+paginationPath, handler)
|
||||
})
|
||||
}
|
||||
|
||||
// Search
|
||||
if blogConfig.Search != nil && blogConfig.Search.Enabled {
|
||||
searchPath := blogPath + blogConfig.Search.Path
|
||||
handler := serveSearch(blog, searchPath)
|
||||
r.With(cacheMiddleware, minifier.Middleware).Get(searchPath, handler)
|
||||
r.With(cacheMiddleware, minifier.Middleware).Post(searchPath, handler)
|
||||
searchResultPath := searchPath + "/" + searchPlaceholder
|
||||
resultHandler := serveSearchResults(blog, searchResultPath)
|
||||
r.With(cacheMiddleware, minifier.Middleware).Get(searchResultPath, resultHandler)
|
||||
r.With(cacheMiddleware, minifier.Middleware).Get(searchResultPath+feedPath, resultHandler)
|
||||
r.With(cacheMiddleware, minifier.Middleware).Get(searchResultPath+paginationPath, resultHandler)
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Use(cacheMiddleware)
|
||||
searchPath := blogPath + blogConfig.Search.Path
|
||||
handler := serveSearch(blog, searchPath)
|
||||
r.Get(searchPath, handler)
|
||||
r.Post(searchPath, handler)
|
||||
searchResultPath := searchPath + "/" + searchPlaceholder
|
||||
resultHandler := serveSearchResults(blog, searchResultPath)
|
||||
r.Get(searchResultPath, resultHandler)
|
||||
r.Get(searchResultPath+feedPath, resultHandler)
|
||||
r.Get(searchResultPath+paginationPath, resultHandler)
|
||||
})
|
||||
}
|
||||
|
||||
// Stats
|
||||
if blogConfig.BlogStats != nil && blogConfig.BlogStats.Enabled {
|
||||
statsPath := blogPath + blogConfig.BlogStats.Path
|
||||
r.With(cacheMiddleware, minifier.Middleware).Get(statsPath, serveBlogStats(blog, statsPath))
|
||||
r.With(cacheMiddleware).Get(statsPath, serveBlogStats(blog, statsPath))
|
||||
}
|
||||
|
||||
// Year / month archives
|
||||
|
@ -270,60 +285,57 @@ func buildHandler() (http.Handler, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, d := range dates {
|
||||
// Year
|
||||
yearPath := blogPath + "/" + fmt.Sprintf("%0004d", d.year)
|
||||
yearHandler := serveDate(blog, yearPath, d.year, 0, 0)
|
||||
r.With(cacheMiddleware, minifier.Middleware).Get(yearPath, yearHandler)
|
||||
r.With(cacheMiddleware, minifier.Middleware).Get(yearPath+feedPath, yearHandler)
|
||||
r.With(cacheMiddleware, minifier.Middleware).Get(yearPath+paginationPath, yearHandler)
|
||||
// Specific month
|
||||
monthPath := yearPath + "/" + fmt.Sprintf("%02d", d.month)
|
||||
monthHandler := serveDate(blog, monthPath, d.year, d.month, 0)
|
||||
r.With(cacheMiddleware, minifier.Middleware).Get(monthPath, monthHandler)
|
||||
r.With(cacheMiddleware, minifier.Middleware).Get(monthPath+feedPath, monthHandler)
|
||||
r.With(cacheMiddleware, minifier.Middleware).Get(monthPath+paginationPath, monthHandler)
|
||||
// Specific day
|
||||
dayPath := monthPath + "/" + fmt.Sprintf("%02d", d.day)
|
||||
dayHandler := serveDate(blog, monthPath, d.year, d.month, d.day)
|
||||
r.With(cacheMiddleware, minifier.Middleware).Get(dayPath, dayHandler)
|
||||
r.With(cacheMiddleware, minifier.Middleware).Get(dayPath+feedPath, dayHandler)
|
||||
r.With(cacheMiddleware, minifier.Middleware).Get(dayPath+paginationPath, dayHandler)
|
||||
// Generic month
|
||||
genericMonthPath := blogPath + "/x/" + fmt.Sprintf("%02d", d.month)
|
||||
genericMonthHandler := serveDate(blog, genericMonthPath, 0, d.month, 0)
|
||||
r.With(cacheMiddleware, minifier.Middleware).Get(genericMonthPath, genericMonthHandler)
|
||||
r.With(cacheMiddleware, minifier.Middleware).Get(genericMonthPath+feedPath, genericMonthHandler)
|
||||
r.With(cacheMiddleware, minifier.Middleware).Get(genericMonthPath+paginationPath, genericMonthHandler)
|
||||
// Specific day
|
||||
genericMonthDayPath := genericMonthPath + "/" + fmt.Sprintf("%02d", d.day)
|
||||
genericMonthDayHandler := serveDate(blog, genericMonthDayPath, 0, d.month, d.day)
|
||||
r.With(cacheMiddleware, minifier.Middleware).Get(genericMonthDayPath, genericMonthDayHandler)
|
||||
r.With(cacheMiddleware, minifier.Middleware).Get(genericMonthDayPath+feedPath, genericMonthDayHandler)
|
||||
r.With(cacheMiddleware, minifier.Middleware).Get(genericMonthDayPath+paginationPath, genericMonthDayHandler)
|
||||
}
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Use(cacheMiddleware)
|
||||
for _, d := range dates {
|
||||
// Year
|
||||
yearPath := blogPath + "/" + fmt.Sprintf("%0004d", d.year)
|
||||
yearHandler := serveDate(blog, yearPath, d.year, 0, 0)
|
||||
r.Get(yearPath, yearHandler)
|
||||
r.Get(yearPath+feedPath, yearHandler)
|
||||
r.Get(yearPath+paginationPath, yearHandler)
|
||||
// Specific month
|
||||
monthPath := yearPath + "/" + fmt.Sprintf("%02d", d.month)
|
||||
monthHandler := serveDate(blog, monthPath, d.year, d.month, 0)
|
||||
r.Get(monthPath, monthHandler)
|
||||
r.Get(monthPath+feedPath, monthHandler)
|
||||
r.Get(monthPath+paginationPath, monthHandler)
|
||||
// Specific day
|
||||
dayPath := monthPath + "/" + fmt.Sprintf("%02d", d.day)
|
||||
dayHandler := serveDate(blog, monthPath, d.year, d.month, d.day)
|
||||
r.Get(dayPath, dayHandler)
|
||||
r.Get(dayPath+feedPath, dayHandler)
|
||||
r.Get(dayPath+paginationPath, dayHandler)
|
||||
// Generic month
|
||||
genericMonthPath := blogPath + "/x/" + fmt.Sprintf("%02d", d.month)
|
||||
genericMonthHandler := serveDate(blog, genericMonthPath, 0, d.month, 0)
|
||||
r.Get(genericMonthPath, genericMonthHandler)
|
||||
r.Get(genericMonthPath+feedPath, genericMonthHandler)
|
||||
r.Get(genericMonthPath+paginationPath, genericMonthHandler)
|
||||
// Specific day
|
||||
genericMonthDayPath := genericMonthPath + "/" + fmt.Sprintf("%02d", d.day)
|
||||
genericMonthDayHandler := serveDate(blog, genericMonthDayPath, 0, d.month, d.day)
|
||||
r.Get(genericMonthDayPath, genericMonthDayHandler)
|
||||
r.Get(genericMonthDayPath+feedPath, genericMonthDayHandler)
|
||||
r.Get(genericMonthDayPath+paginationPath, genericMonthDayHandler)
|
||||
}
|
||||
})
|
||||
|
||||
// Blog
|
||||
if !blogConfig.PostAsHome {
|
||||
var mw []func(http.Handler) http.Handler
|
||||
if appConfig.ActivityPub.Enabled {
|
||||
mw = []func(http.Handler) http.Handler{manipulateAsPath, cacheMiddleware, minifier.Middleware}
|
||||
} else {
|
||||
mw = []func(http.Handler) http.Handler{cacheMiddleware, minifier.Middleware}
|
||||
}
|
||||
handler := serveHome(blog, blogPath)
|
||||
r.With(mw...).Get(fullBlogPath, handler)
|
||||
r.With(cacheMiddleware, minifier.Middleware).Get(fullBlogPath+feedPath, handler)
|
||||
r.With(cacheMiddleware, minifier.Middleware).Get(blogPath+paginationPath, handler)
|
||||
r.With(manipulateAsPath, cacheMiddleware).Get(fullBlogPath, handler)
|
||||
r.With(cacheMiddleware).Get(fullBlogPath+feedPath, handler)
|
||||
r.With(cacheMiddleware).Get(blogPath+paginationPath, handler)
|
||||
}
|
||||
|
||||
// Custom pages
|
||||
for _, cp := range blogConfig.CustomPages {
|
||||
handler := serveCustomPage(blogConfig, cp)
|
||||
if cp.Cache {
|
||||
r.With(cacheMiddleware, minifier.Middleware).Get(cp.Path, handler)
|
||||
r.With(cacheMiddleware).Get(cp.Path, handler)
|
||||
} else {
|
||||
r.With(minifier.Middleware).Get(cp.Path, handler)
|
||||
r.Get(cp.Path, handler)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -338,7 +350,7 @@ func buildHandler() (http.Handler, error) {
|
|||
|
||||
// Editor
|
||||
r.Route(blogPath+"/editor", func(mpRouter chi.Router) {
|
||||
mpRouter.Use(middleware.NoCache, minifier.Middleware, authMiddleware)
|
||||
mpRouter.Use(authMiddleware)
|
||||
mpRouter.Get("/", serveEditor(blog))
|
||||
mpRouter.Post("/", serveEditorPost(blog))
|
||||
})
|
||||
|
@ -347,25 +359,28 @@ func buildHandler() (http.Handler, error) {
|
|||
if commentsConfig := blogConfig.Comments; commentsConfig != nil && commentsConfig.Enabled {
|
||||
commentsPath := blogPath + "/comment"
|
||||
r.Route(commentsPath, func(cr chi.Router) {
|
||||
cr.With(cacheMiddleware, minifier.Middleware).Get("/{id:[0-9]+}", serveComment(blog))
|
||||
cr.With(cacheMiddleware).Get("/{id:[0-9]+}", serveComment(blog))
|
||||
cr.With(captchaMiddleware).Post("/", createComment(blog, commentsPath))
|
||||
// Admin
|
||||
cr.With(minifier.Middleware, authMiddleware).Get("/", commentsAdmin)
|
||||
cr.With(authMiddleware).Post("/delete", commentsAdminDelete)
|
||||
cr.Group(func(r chi.Router) {
|
||||
r.Use(authMiddleware)
|
||||
r.Get("/", commentsAdmin)
|
||||
r.Post("/delete", commentsAdminDelete)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Sitemap
|
||||
r.With(cacheMiddleware, minifier.Middleware).Get(sitemapPath, serveSitemap)
|
||||
r.With(cacheMiddleware).Get(sitemapPath, serveSitemap)
|
||||
|
||||
// Robots.txt - doesn't need cache, because it's too simple
|
||||
r.Get("/robots.txt", serveRobotsTXT)
|
||||
|
||||
// Check redirects, then serve 404
|
||||
r.With(cacheMiddleware, checkRegexRedirects, minifier.Middleware).NotFound(serve404)
|
||||
r.With(cacheMiddleware, checkRegexRedirects).NotFound(serve404)
|
||||
|
||||
r.With(minifier.Middleware).MethodNotAllowed(func(rw http.ResponseWriter, r *http.Request) {
|
||||
r.MethodNotAllowed(func(rw http.ResponseWriter, r *http.Request) {
|
||||
serveError(rw, r, "", http.StatusMethodNotAllowed)
|
||||
})
|
||||
|
||||
|
|
71
hugo.go
71
hugo.go
|
@ -1,71 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/jeremywohl/flatten"
|
||||
"github.com/spf13/cast"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
func parseHugoFile(fileContent string) (p *post, aliases []string, e error) {
|
||||
frontmatterSep := "---\n"
|
||||
frontmatter := ""
|
||||
if split := strings.Split(fileContent, frontmatterSep); len(split) > 2 {
|
||||
frontmatter = split[1]
|
||||
}
|
||||
p = &post{
|
||||
Content: strings.TrimPrefix(fileContent, frontmatterSep+frontmatter+frontmatterSep),
|
||||
Parameters: map[string][]string{},
|
||||
}
|
||||
// Parse frontmatter
|
||||
meta := map[string]interface{}{}
|
||||
err := yaml.Unmarshal([]byte(frontmatter), &meta)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
flat, err := flatten.Flatten(meta, "", flatten.DotStyle)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
// Read dates
|
||||
p.Published = cast.ToString(flat["date"])
|
||||
p.Updated = cast.ToString(flat["lastmod"])
|
||||
// Read parameters
|
||||
for _, fm := range appConfig.Hugo.Frontmatter {
|
||||
var values []string
|
||||
for fk, value := range flat {
|
||||
if strings.HasPrefix(fk, fm.Meta) {
|
||||
trimmed := strings.TrimPrefix(fk, fm.Meta)
|
||||
if len(trimmed) == 0 {
|
||||
values = append(values, cast.ToString(value))
|
||||
} else {
|
||||
trimmed = strings.TrimPrefix(trimmed, ".")
|
||||
if _, e := strconv.Atoi(trimmed); e == nil {
|
||||
values = append(values, cast.ToString(value))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(values) > 0 {
|
||||
p.Parameters[fm.Parameter] = values
|
||||
}
|
||||
}
|
||||
// Parse redirects
|
||||
for fk, value := range flat {
|
||||
if strings.HasPrefix(fk, "aliases") {
|
||||
trimmed := strings.TrimPrefix(fk, "aliases")
|
||||
if len(trimmed) == 0 {
|
||||
aliases = append(aliases, cast.ToString(value))
|
||||
} else {
|
||||
trimmed = strings.TrimPrefix(trimmed, ".")
|
||||
if _, e := strconv.Atoi(trimmed); e == nil {
|
||||
aliases = append(aliases, cast.ToString(value))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Return post
|
||||
return p, aliases, nil
|
||||
}
|
|
@ -134,16 +134,11 @@ func indieAuthVerification(w http.ResponseWriter, r *http.Request) {
|
|||
serveError(w, r, "Authentication not valid", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
res := &tokenResponse{
|
||||
b, _ := json.Marshal(tokenResponse{
|
||||
Me: appConfig.Server.PublicAddress,
|
||||
}
|
||||
w.Header().Add(contentType, contentTypeJSONUTF8)
|
||||
err = json.NewEncoder(w).Encode(res)
|
||||
if err != nil {
|
||||
w.Header().Del(contentType)
|
||||
serveError(w, r, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
})
|
||||
w.Header().Set(contentType, contentTypeJSONUTF8)
|
||||
_, _ = writeMinified(w, contentTypeJSON, b)
|
||||
}
|
||||
|
||||
func indieAuthToken(w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -159,13 +154,9 @@ func indieAuthToken(w http.ResponseWriter, r *http.Request) {
|
|||
Me: appConfig.Server.PublicAddress,
|
||||
ClientID: data.ClientID,
|
||||
}
|
||||
w.Header().Add(contentType, contentTypeJSONUTF8)
|
||||
err = json.NewEncoder(w).Encode(res)
|
||||
if err != nil {
|
||||
w.Header().Del(contentType)
|
||||
serveError(w, r, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
b, _ := json.Marshal(res)
|
||||
w.Header().Set(contentType, contentTypeJSONUTF8)
|
||||
_, _ = writeMinified(w, contentTypeJSON, b)
|
||||
return
|
||||
} else if r.Method == http.MethodPost {
|
||||
if err := r.ParseForm(); err != nil {
|
||||
|
@ -216,13 +207,9 @@ func indieAuthToken(w http.ResponseWriter, r *http.Request) {
|
|||
Scope: strings.Join(data.Scopes, " "),
|
||||
Me: appConfig.Server.PublicAddress,
|
||||
}
|
||||
w.Header().Add(contentType, contentTypeJSONUTF8)
|
||||
err = json.NewEncoder(w).Encode(res)
|
||||
if err != nil {
|
||||
w.Header().Del(contentType)
|
||||
serveError(w, r, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
b, _ := json.Marshal(res)
|
||||
w.Header().Set(contentType, contentTypeJSONUTF8)
|
||||
_, _ = writeMinified(w, contentTypeJSON, b)
|
||||
return
|
||||
}
|
||||
serveError(w, r, "", http.StatusBadRequest)
|
||||
|
|
15
micropub.go
15
micropub.go
|
@ -25,11 +25,12 @@ type micropubConfig struct {
|
|||
func serveMicropubQuery(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.URL.Query().Get("q") {
|
||||
case "config":
|
||||
w.Header().Add(contentType, contentTypeJSONUTF8)
|
||||
w.Header().Set(contentType, contentTypeJSONUTF8)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_ = json.NewEncoder(w).Encode(µpubConfig{
|
||||
b, _ := json.Marshal(µpubConfig{
|
||||
MediaEndpoint: appConfig.Server.PublicAddress + micropubPath + micropubMediaSubPath,
|
||||
})
|
||||
_, _ = writeMinified(w, contentTypeJSON, b)
|
||||
case "source":
|
||||
var mf interface{}
|
||||
if urlString := r.URL.Query().Get("url"); urlString != "" {
|
||||
|
@ -61,9 +62,10 @@ func serveMicropubQuery(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
mf = list
|
||||
}
|
||||
w.Header().Add(contentType, contentTypeJSONUTF8)
|
||||
w.Header().Set(contentType, contentTypeJSONUTF8)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_ = json.NewEncoder(w).Encode(mf)
|
||||
b, _ := json.Marshal(mf)
|
||||
_, _ = writeMinified(w, contentTypeJSON, b)
|
||||
case "category":
|
||||
allCategories := []string{}
|
||||
for blog := range appConfig.Blogs {
|
||||
|
@ -74,11 +76,12 @@ func serveMicropubQuery(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
allCategories = append(allCategories, values...)
|
||||
}
|
||||
w.Header().Add(contentType, contentTypeJSONUTF8)
|
||||
w.Header().Set(contentType, contentTypeJSONUTF8)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_ = json.NewEncoder(w).Encode(map[string]interface{}{
|
||||
b, _ := json.Marshal(map[string]interface{}{
|
||||
"categories": allCategories,
|
||||
})
|
||||
_, _ = writeMinified(w, contentTypeJSON, b)
|
||||
default:
|
||||
serve404(w, r)
|
||||
}
|
||||
|
|
15
minify.go
15
minify.go
|
@ -1,6 +1,8 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/tdewolff/minify/v2"
|
||||
mCss "github.com/tdewolff/minify/v2/css"
|
||||
mHtml "github.com/tdewolff/minify/v2/html"
|
||||
|
@ -17,7 +19,14 @@ func initMinify() {
|
|||
minifier.AddFunc("text/css", mCss.Minify)
|
||||
minifier.AddFunc("text/xml", mXml.Minify)
|
||||
minifier.AddFunc("application/javascript", mJs.Minify)
|
||||
minifier.AddFunc("application/rss+xml", mXml.Minify)
|
||||
minifier.AddFunc("application/atom+xml", mXml.Minify)
|
||||
minifier.AddFunc("application/feed+json", mJson.Minify)
|
||||
minifier.AddFunc(contentTypeRSS, mXml.Minify)
|
||||
minifier.AddFunc(contentTypeATOM, mXml.Minify)
|
||||
minifier.AddFunc(contentTypeJSONFeed, mJson.Minify)
|
||||
minifier.AddFunc(contentTypeAS, mJson.Minify)
|
||||
}
|
||||
|
||||
func writeMinified(w io.Writer, mediatype string, b []byte) (int, error) {
|
||||
mw := minifier.Writer(mediatype, w)
|
||||
defer func() { mw.Close() }()
|
||||
return mw.Write(b)
|
||||
}
|
||||
|
|
16
nodeinfo.go
16
nodeinfo.go
|
@ -6,24 +6,23 @@ import (
|
|||
)
|
||||
|
||||
func serveNodeInfoDiscover(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set(contentType, contentTypeJSONUTF8)
|
||||
nid := map[string]interface{}{
|
||||
b, _ := json.Marshal(map[string]interface{}{
|
||||
"links": []map[string]interface{}{
|
||||
{
|
||||
"href": appConfig.Server.PublicAddress + "/nodeinfo",
|
||||
"rel": "http://nodeinfo.diaspora.software/ns/schema/2.1",
|
||||
},
|
||||
},
|
||||
}
|
||||
_ = json.NewEncoder(w).Encode(&nid)
|
||||
})
|
||||
w.Header().Set(contentType, contentTypeJSONUTF8)
|
||||
_, _ = writeMinified(w, contentTypeJSON, b)
|
||||
}
|
||||
|
||||
func serveNodeInfo(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set(contentType, contentTypeJSONUTF8)
|
||||
localPosts, _ := countPosts(&postsRequestConfig{
|
||||
status: statusPublished,
|
||||
})
|
||||
nid := map[string]interface{}{
|
||||
b, _ := json.Marshal(map[string]interface{}{
|
||||
"version": "2.1",
|
||||
"software": map[string]interface{}{
|
||||
"name": "goblog",
|
||||
|
@ -41,6 +40,7 @@ func serveNodeInfo(w http.ResponseWriter, r *http.Request) {
|
|||
"webmention",
|
||||
},
|
||||
"metadata": map[string]interface{}{},
|
||||
}
|
||||
_ = json.NewEncoder(w).Encode(&nid)
|
||||
})
|
||||
w.Header().Set(contentType, contentTypeJSONUTF8)
|
||||
_, _ = writeMinified(w, contentTypeJSON, b)
|
||||
}
|
||||
|
|
|
@ -14,7 +14,9 @@ func allPostAliases() ([]string, error) {
|
|||
for rows.Next() {
|
||||
var path string
|
||||
_ = rows.Scan(&path)
|
||||
aliases = append(aliases, path)
|
||||
if path != "" {
|
||||
aliases = append(aliases, path)
|
||||
}
|
||||
}
|
||||
return aliases, nil
|
||||
}
|
||||
|
|
|
@ -396,7 +396,9 @@ func allPostPaths(status postStatus) ([]string, error) {
|
|||
for rows.Next() {
|
||||
var path string
|
||||
_ = rows.Scan(&path)
|
||||
postPaths = append(postPaths, path)
|
||||
if path != "" {
|
||||
postPaths = append(postPaths, path)
|
||||
}
|
||||
}
|
||||
return postPaths, nil
|
||||
}
|
||||
|
|
|
@ -264,8 +264,8 @@ func render(w http.ResponseWriter, template string, data *renderData) {
|
|||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
// Set content type (needed for minification middleware
|
||||
// Set content type
|
||||
w.Header().Set(contentType, contentTypeHTMLUTF8)
|
||||
// Write buffered response
|
||||
_, _ = w.Write(buffer.Bytes())
|
||||
_, _ = writeMinified(w, contentTypeHTML, buffer.Bytes())
|
||||
}
|
||||
|
|
|
@ -35,5 +35,5 @@ func serveSitemap(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
sm.Add(item)
|
||||
}
|
||||
_, _ = sm.WriteTo(w)
|
||||
_, _ = sm.WriteTo(w) // Already minified
|
||||
}
|
||||
|
|
|
@ -98,6 +98,6 @@ func serveAsset(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
w.Header().Set("Cache-Control", "public,max-age=31536000,immutable")
|
||||
w.Header().Set(contentType, af.contentType)
|
||||
w.Header().Set(contentType, af.contentType+charsetUtf8Suffix)
|
||||
_, _ = w.Write(af.body)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue