diff options
| author | Mitchell Riedstra <mitch@riedstra.dev> | 2022-12-03 13:38:05 -0500 |
|---|---|---|
| committer | Mitchell Riedstra <mitch@riedstra.dev> | 2022-12-03 13:39:47 -0500 |
| commit | 10c60b3c9ba2c17419534cf4089328a66568e4f1 (patch) | |
| tree | 33e6ecedfc3dec7d96488878291179c8a593e779 | |
| parent | d6f60ce24e123ee83b73f6c9dbe8c4b9af5c629e (diff) | |
| download | go-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.go | 47 | ||||
| -rw-r--r-- | cmd/server/middleware.go | 32 | ||||
| -rw-r--r-- | go.mod | 12 | ||||
| -rw-r--r-- | go.sum | 62 | ||||
| -rw-r--r-- | page/page.go | 14 | ||||
| -rw-r--r-- | page/renderJson.go | 118 | ||||
| -rw-r--r-- | page/renderMarkdown.go | 69 |
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) - } -} -*/ @@ -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 ) @@ -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) +} |
