go__sqs_demo/back/web/routes.go

118 lines
3.5 KiB
Go

package web
import (
_ "embed"
"fmt"
"html/template"
"net/http"
"path/filepath"
"time"
"github.com/Masterminds/sprig/v3"
"github.com/davecgh/go-spew/spew"
"github.com/fgm/izidic"
"github.com/gin-contrib/sessions"
"github.com/gin-contrib/sessions/cookie"
"github.com/gin-gonic/gin"
"github.com/utrack/gin-csrf"
"code.osinet.fr/fgm/sqs_demo/back/services"
"code.osinet.fr/fgm/sqs_demo/back/services/redriver"
"code.osinet.fr/fgm/sqs_demo/front"
)
func SetupRoutes(rd redriver.Redriver, ms redriver.MessageStore, renderer *template.Template, storeSecret, csrfSecret []byte, prefix string) *gin.Engine {
const assetsPrefix = "/assets/"
r := gin.Default()
r.SetHTMLTemplate(renderer)
_ = r.SetTrustedProxies(nil)
store := cookie.NewStore(storeSecret)
r.Use(sessions.Sessions("defaultsession", store))
mw := csrf.Middleware(csrf.Options{
Secret: string(csrfSecret),
ErrorFunc: func(c *gin.Context) {
c.String(http.StatusBadRequest, "CSRF token does not match")
c.Abort()
},
TokenGetter: nil,
})
// Done
r.StaticFS(assetsPrefix, PrefixFileSystem(assetsPrefix, http.FS(front.Assets)))
r.GET("/queue", gin.WrapH(http.RedirectHandler("/", http.StatusMovedPermanently)))
r.GET("/queue/:name/confirm", mw, makeConfirmHandler()) // Needs mw to set token.
// Back done, front WIP
r.GET("/queue/:name", makeQueueHandler(rd, ms))
// JSON done
r.GET("/", makeHomeHandler(rd, prefix))
// TODO
r.POST("/queue/:name/delete", mw, makeDeleteHandler(rd)) // Needs mw to check token.
r.POST("/queue/:name/purge", mw, makePurgeHandler(rd)) // Needs mw to check token.
r.POST("/queue/:name/redrive", mw, makeRedriveHandler(rd, ms)) // Needs mw to check token.
return r
}
func HttpService(dic *izidic.Container) (any, error) {
csrfSecret := dic.MustParam(services.PCSRFSecret).([]byte)
prefix := dic.MustParam(services.PPrefix).(string)
storeSecret := dic.MustParam(services.PStoreSecret).([]byte)
rd := dic.MustService(services.SvcRedriver).(redriver.Redriver)
re := dic.MustService(services.SvcRenderer).(*template.Template)
ms := dic.MustService(services.SvcMessageStore).(redriver.MessageStore)
return SetupRoutes(rd, ms, re, storeSecret, csrfSecret, prefix), nil
}
func RendererService(_ *izidic.Container) (any, error) {
var err error
renderer := template.New("redriver").Funcs(template.FuncMap{
"dump": func(args ...any) template.HTML {
return "<pre>" + template.HTML(spew.Sdump(args...)) + "</pre>\n"
},
"timestamp": func(ts int64) time.Time {
return time.Unix(ts, 0)
},
"nameFromARN": redriver.NameFromARNString,
}).Funcs(sprig.FuncMap())
for _, tpl := range []struct {
name string
value string
}{
{"confirm", front.Confirm},
{"flashes", front.Flashes},
{"home", front.Home},
{"queue-get", front.QueueGet}, // Includes queue-item.
{"500", front.Err500},
} {
renderer, err = renderer.New(tpl.name).Parse(tpl.value)
if err != nil {
return nil, fmt.Errorf("failed parsing %q template: %w", tpl.name, err)
}
}
return renderer, nil
}
// PrefixFileSystem converts a http.FileSystem by serving it requests prefixed
// by the passed prefix, allowing rooted static directories matching the name
// of an embed.FS.
func PrefixFileSystem(prefix string, ifs http.FileSystem) http.FileSystem {
return &prefixedFS{
prefix: prefix,
ifs: ifs,
}
}
type prefixedFS struct {
prefix string
ifs http.FileSystem
}
// Open implements http.FileSystem
func (pfs *prefixedFS) Open(name string) (http.File, error) {
return pfs.ifs.Open(filepath.Join(pfs.prefix, name))
}