aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMitchell Riedstra <mitch@riedstra.dev>2022-12-03 13:38:05 -0500
committerMitchell Riedstra <mitch@riedstra.dev>2022-12-03 13:39:47 -0500
commit10c60b3c9ba2c17419534cf4089328a66568e4f1 (patch)
tree33e6ecedfc3dec7d96488878291179c8a593e779
parentd6f60ce24e123ee83b73f6c9dbe8c4b9af5c629e (diff)
downloadgo-website-10c60b3c9ba2c17419534cf4089328a66568e4f1.tar.gz
go-website-10c60b3c9ba2c17419534cf4089328a66568e4f1.tar.xz
Add a couple handlers to serve up JSON and markdown
-rw-r--r--cmd/server/handlers.go47
-rw-r--r--cmd/server/middleware.go32
-rw-r--r--go.mod12
-rw-r--r--go.sum62
-rw-r--r--page/page.go14
-rw-r--r--page/renderJson.go118
-rw-r--r--page/renderMarkdown.go69
7 files changed, 297 insertions, 57 deletions
diff --git a/cmd/server/handlers.go b/cmd/server/handlers.go
index c44c19c..d4b7140 100644
--- a/cmd/server/handlers.go
+++ b/cmd/server/handlers.go
@@ -28,9 +28,23 @@ func (a *App) ServeHTTP(w http.ResponseWriter, r *http.Request) {
rediscache.HandleWithParams(a.redisPool, a.RedisKey,
http.HandlerFunc(a.FeedHandler)))
+ rtr.PathPrefix("/_json/").Handler(
+ rediscache.HandleWithParams(a.redisPool, a.RedisKey,
+ http.StripPrefix("/_json", http.HandlerFunc(a.PageJsonHandler))))
+
+ rtr.PathPrefix("/_md/").Handler(
+ rediscache.HandleWithParams(a.redisPool, a.RedisKey,
+ http.StripPrefix("/_md", http.HandlerFunc(a.PageMarkdownHandler))))
+
rtr.PathPrefix("/").Handler(rediscache.Handle(
a.redisPool, a.RedisKey, http.HandlerFunc(a.PageHandler)))
} else {
+ rtr.PathPrefix("/_md/").Handler(http.StripPrefix("/_md",
+ http.HandlerFunc(a.PageMarkdownHandler)))
+
+ rtr.PathPrefix("/_json/").Handler(http.StripPrefix("/_json",
+ http.HandlerFunc(a.PageJsonHandler)))
+
rtr.PathPrefix(fmt.Sprintf("/%s/{tag}", a.FeedPrefix)).HandlerFunc(
a.FeedHandler)
@@ -68,6 +82,39 @@ func (a *App) PageHandler(w http.ResponseWriter, r *http.Request) {
"LoggedIn": loggedIn,
})
}
+func (a *App) PageJsonHandler(w http.ResponseWriter, r *http.Request) {
+ u := r.URL.Path
+ if u == "/" {
+ u = "/index"
+ }
+
+ // Skip template directory
+ if strings.HasPrefix(u[1:], filepath.Clean(page.TemplateDirectory)) {
+ page.Render4xx(w, r, map[string]interface{}{}, 404)
+ return
+ }
+
+ u = filepath.Join(".", u)
+
+ page.RenderJson(w, r, u, map[string]interface{}{}, 200)
+}
+
+func (a *App) PageMarkdownHandler(w http.ResponseWriter, r *http.Request) {
+ u := r.URL.Path
+ if u == "/" {
+ u = "/index"
+ }
+
+ // Skip template directory
+ if strings.HasPrefix(u[1:], filepath.Clean(page.TemplateDirectory)) {
+ page.Render4xx(w, r, map[string]interface{}{}, 404)
+ return
+ }
+
+ u = filepath.Join(".", u)
+
+ page.RenderMarkdown(w, r, u, map[string]interface{}{}, 200)
+}
func (a *App) RebuildIndexHandler(w http.ResponseWriter, r *http.Request) {
u := r.URL.Path
diff --git a/cmd/server/middleware.go b/cmd/server/middleware.go
index 0d332cd..7ba34cf 100644
--- a/cmd/server/middleware.go
+++ b/cmd/server/middleware.go
@@ -7,7 +7,7 @@ import (
"net/url"
"time"
- jwt "github.com/dgrijalva/jwt-go"
+ jwt "github.com/golang-jwt/jwt/v4"
"riedstra.dev/mitch/go-website/page"
"riedstra.dev/mitch/go-website/users"
)
@@ -166,33 +166,3 @@ func (a *App) RequiresLogin(next http.Handler) http.Handler {
})
}
-
-/*
-// ConditionalMiddleware is used to select one handler or another based on
-// a test function. If the test function returns true, use handler A, otherwise B.
-// This allows the test condition to only be run when the handler is selected
-// rather than trying to do this as a top level and ending up with a condition
-// that is tested on every single request, regardless of whether or not
-// the specific handler is selected
-type ConditionalMiddleware struct {
- A, B http.Handler
- Test func(r *http.Request) bool
-}
-
-func NewConditionalMiddleware(test func(r *http.Request) bool,
- A, B http.Handler) http.Handler {
- return &ConditionalMiddleware{
- Test: test,
- A: A,
- B: B,
- }
-}
-
-func (cm *ConditionalMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
- if cm.Test(r) {
- cm.A.ServeHTTP(w, r)
- } else {
- cm.B.ServeHTTP(w, r)
- }
-}
-*/
diff --git a/go.mod b/go.mod
index bf98b60..9d5dedf 100644
--- a/go.mod
+++ b/go.mod
@@ -3,15 +3,17 @@ module riedstra.dev/mitch/go-website
go 1.13
require (
- github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect
- github.com/gomodule/redigo v1.8.5 // indirect
+ github.com/golang-jwt/jwt/v4 v4.4.2
+ github.com/golang/protobuf v1.5.2 // indirect
+ github.com/gomodule/redigo v1.8.9
github.com/gorilla/mux v1.8.0
github.com/kr/pretty v0.1.0 // indirect
github.com/russross/blackfriday v2.0.0+incompatible
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
- github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect
- golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e // indirect
+ github.com/vmihailenco/msgpack v4.0.4+incompatible
+ golang.org/x/crypto v0.3.0
google.golang.org/appengine v1.6.7 // indirect
+ google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
- gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776
+ gopkg.in/yaml.v3 v3.0.1
)
diff --git a/go.sum b/go.sum
index f6dae73..02968bc 100644
--- a/go.sum
+++ b/go.sum
@@ -1,16 +1,19 @@
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
-github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
-github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
+github.com/golang-jwt/jwt/v4 v4.4.2 h1:rcc4lwaZgFMCZ5jxF9ABolDcIHdBytAFgqFPbSJQAYs=
+github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/gomodule/redigo v1.8.5 h1:nRAxCa+SVsyjSBrtZmG/cqb6VbTmuRzpg/PoTFlpumc=
-github.com/gomodule/redigo v1.8.5/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0=
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
+github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/gomodule/redigo v1.8.9 h1:Sl3u+2BI/kk+VEatbj0scLdrFhjPmbxOc1myhDP41ws=
+github.com/gomodule/redigo v1.8.9/go.mod h1:7ArFNvsTjH8GMMzB4uy1snslv2BwmginuMs06a1uzZE=
+github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
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/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw=
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=
@@ -20,33 +23,54 @@ github.com/russross/blackfriday v2.0.0+incompatible h1:cBXrhZNUf9C+La9/YpS+UHpUT
github.com/russross/blackfriday v2.0.0+incompatible/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
-github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
-github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI=
github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
+github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e h1:T8NU3HyQ8ClP4SEE+KbFlg6n0NhuTsN4MyznaarGsZM=
-golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/net v0.0.0-20190603091049-60506f45cf65 h1:+rhAzEzT3f4JtomfC371qB+0Ola2caSKcY69NUBZrRQ=
+golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.3.0 h1:a06MkbcxBrEFc0w0QIZWXrH/9cCX6KJyWbBOIwAn+7A=
+golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
+golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
-golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU=
+golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
-golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
+google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
-gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=
-gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/page/page.go b/page/page.go
index d34a1f7..29b35bc 100644
--- a/page/page.go
+++ b/page/page.go
@@ -55,7 +55,10 @@ type Page struct {
Date *PageTime
Published bool
Vars map[string]interface{}
- markdown []byte
+ // Keys of vars to be included when RenderJson is called, all vars are
+ // omitted if empty.
+ JsonVars []string
+ markdown []byte
}
// Global is meant to be supplied by external users of this package to populate
@@ -232,6 +235,13 @@ func (p *Page) Read() error {
// markdown file, then runs it through the markdown parser. Typically
// this is called in the base template.
func (p *Page) RenderBody() (string, error) {
+ s, err := p.GetMarkdown()
+ return string(blackfriday.Run([]byte(s))), err
+}
+
+// GetMarkdown renders and executes a template from the body of the
+// markdown file, then simply returns the unrendered markdown.
+func (p *Page) GetMarkdown() (string, error) {
buf := &bytes.Buffer{}
t, err := template.New("Body").Funcs(Funcs).Parse(string(p.markdown))
@@ -245,7 +255,7 @@ func (p *Page) RenderBody() (string, error) {
return "", fmt.Errorf("template execute; %w", err)
}
- return string(blackfriday.Run(buf.Bytes())), nil
+ return buf.String(), nil
}
func (p Page) String() string {
diff --git a/page/renderJson.go b/page/renderJson.go
new file mode 100644
index 0000000..52e707d
--- /dev/null
+++ b/page/renderJson.go
@@ -0,0 +1,118 @@
+package page
+
+import (
+ "bytes"
+ "encoding/json"
+ "errors"
+ "io/fs"
+ "net/http"
+ "path/filepath"
+)
+
+// RenderJson is analogous to Render, though it renders the page,
+// as a JSON key "content", optionally from the YAML it'll include
+// additional keys in the json if specified under the 'pageJson' key.
+// E.g.
+// ---
+// title: Some page
+// description: Some page desc
+// jsonvars:
+// - includeMeInJSON
+// vars:
+// notIncluded: some value
+// includeMeInJSON:
+// some: arbitrary
+// data: to
+// send: down
+// |--
+// My page content, wee!
+func RenderJson(w http.ResponseWriter, r *http.Request,
+ path string, vars map[string]interface{}, statusCode int) {
+ u := getURLPath(r)
+
+ u = filepath.Join(".", u)
+
+ // Sepcifically use the specified path for the page
+ p := NewPage(path)
+
+ if vars != nil {
+ p.Vars = vars
+ }
+
+ out := map[string]interface{}{}
+
+ buf := &bytes.Buffer{}
+ err := p.Render(buf)
+ if err != nil {
+ if errors.Is(err, fs.ErrNotExist) {
+ renderJsonErr(w, r, "Not found", http.StatusNotFound)
+
+ return
+ }
+
+ Logger.Printf("%s %s path: %s rendering encountered: %s",
+ r.RemoteAddr,
+ r.Method,
+ u,
+ err)
+ renderJsonErr(w, r, "Internal server error",
+ http.StatusInternalServerError)
+
+ return
+ }
+
+ if r.URL.Query().Get("content") == "1" {
+ out["Content"] = buf.String()
+ }
+
+ if r.URL.Query().Get("markdown") == "1" {
+ // Tossing the error, since it would've been revealed above
+ md, _ := p.GetMarkdown()
+ out["Markdown"] = md
+ }
+
+ // Make a "set" of keys
+ keys := map[string]struct{}{}
+ for _, k := range p.JsonVars {
+ keys[k] = struct{}{}
+ }
+
+ // And chuck the keys specified into the output
+ for k, v := range p.Vars {
+ _, ok := keys[k]
+ if ok {
+ out[k] = v
+ }
+ }
+
+ w.WriteHeader(statusCode)
+
+ enc := json.NewEncoder(w)
+ enc.SetIndent("", " ")
+ enc.SetEscapeHTML(false)
+
+ err = enc.Encode(out)
+ if err != nil {
+ Logger.Printf("%s %s %d %s: while writing buf: %s",
+ r.RemoteAddr,
+ r.Method,
+ statusCode,
+ u,
+ err)
+
+ return
+ }
+
+ Logger.Printf("%s %s %d %s", r.RemoteAddr, r.Method, statusCode, u)
+}
+
+func renderJsonErr(w http.ResponseWriter, r *http.Request, msg string,
+ statusCode int) {
+ enc := json.NewEncoder(w)
+ w.WriteHeader(statusCode)
+ _ = enc.Encode(&struct {
+ Status string
+ }{
+ Status: msg,
+ })
+}
diff --git a/page/renderMarkdown.go b/page/renderMarkdown.go
new file mode 100644
index 0000000..c876169
--- /dev/null
+++ b/page/renderMarkdown.go
@@ -0,0 +1,69 @@
+package page
+
+import (
+ "bytes"
+ "errors"
+ "io/fs"
+ "net/http"
+ "path/filepath"
+)
+
+// RenderMarkdown is analogous to Render, except it spits out rendered markdown
+// as text/plain
+func RenderMarkdown(w http.ResponseWriter, r *http.Request,
+ path string, vars map[string]interface{}, statusCode int) {
+ u := getURLPath(r)
+
+ u = filepath.Join(".", u)
+
+ // Sepcifically use the specified path for the page
+ p := NewPage(path)
+
+ if vars != nil {
+ p.Vars = vars
+ }
+
+ buf := &bytes.Buffer{}
+
+ err := p.Render(buf)
+ if err != nil {
+ if errors.Is(err, fs.ErrNotExist) {
+ w.WriteHeader(http.StatusNotFound)
+ w.Header().Set("Content-type", "text/plain")
+ w.Write([]byte("Not found"))
+
+ return
+ }
+
+ Logger.Printf("%s %s path: %s rendering encountered: %s",
+ r.RemoteAddr,
+ r.Method,
+ u,
+ err)
+ w.WriteHeader(http.StatusInternalServerError)
+ w.Header().Set("Content-type", "text/plain")
+ w.Write([]byte("Internal server error"))
+
+ return
+ }
+
+ // Error was handled above
+ md, _ := p.GetMarkdown()
+
+ w.WriteHeader(statusCode)
+ w.Header().Set("Content-type", "text/plain")
+
+ _, err = w.Write([]byte(md))
+ if err != nil {
+ Logger.Printf("%s %s %d %s: while writing buf: %s",
+ r.RemoteAddr,
+ r.Method,
+ statusCode,
+ u,
+ err)
+
+ return
+ }
+
+ Logger.Printf("%s %s %d %s", r.RemoteAddr, r.Method, statusCode, u)
+}