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 "
" + template.HTML(spew.Sdump(args...)) + "
\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)) }