save "create sync group" table in database

This commit is contained in:
2026-01-11 05:19:20 -07:00
parent a7c8fe4d64
commit 889aead6b6
28 changed files with 1396 additions and 408 deletions
+102 -29
View File
@@ -11,21 +11,24 @@ import (
"github.com/angelbeltran/templater"
"ruben/inventory2/internal/consts"
"ruben/inventory2/internal/domains/accounts"
"ruben/inventory2/internal/domains/authentication"
etsy_platform "ruben/inventory2/internal/domains/platforms/etsy"
"ruben/inventory2/internal/domains/raw_events"
"ruben/inventory2/internal/site/middleware"
"ruben/inventory2/internal/site/response"
)
type Server struct {
http.Handler
contentDir string
templater *templater.Templater
rawEvents *raw_events.Store
accts *accounts.Store
etsy *etsy_platform.Platform
auth *authentication.Authenticator
contentDir string
templater *templater.Templater
rawEvents *raw_events.Store
accts *accounts.Store
etsy *etsy_platform.Platform
auth *authentication.Authenticator
authMiddleware *middleware.Auth
}
func NewServer(
@@ -35,14 +38,28 @@ func NewServer(
etsy *etsy_platform.Platform,
auth *authentication.Authenticator,
) *Server {
mux := http.NewServeMux()
mux := response.NewMux(func(fn response.HandlerFunc) response.HandlerFunc {
return func(r *http.Request) (response.Response, error) {
res, err := fn(r)
if err != nil {
status := response.GetStatusFromError(err)
// TODO: get better logger
fmt.Printf("[ERROR]: %d: %s; %s\n", status, r.URL, err)
}
return res, err
}
})
s := &Server{
Handler: mux,
contentDir: contentDir,
templater: templater.NewTemplater(
contentDir+"/templates",
func() template.FuncMap {
return template.FuncMap{
// paths
"buildSitePath": func(parts ...any) string {
strParts := make([]string, len(parts))
for i, p := range parts {
@@ -60,18 +77,30 @@ func NewServer(
return strings.Split(strings.TrimSuffix(strings.TrimPrefix(p, "/"), "/"), "/")
},
"prettyPrintJSON": func(j json.RawMessage) string {
b, err := json.MarshalIndent(j, " ", "")
if err != nil {
return string(j)
// params
"addPathParam": func(k string, v any, args map[string]any) (map[string]any, error) {
pathParams, ok := args["PathParams"].(map[string]string)
if !ok {
return nil, fmt.Errorf("PathParams no set are args: %v", args)
}
return string(b)
pathParams[k] = fmt.Sprint(v)
return args, nil
},
// parsing
"parseInt": func(s string) (int, error) {
return strconv.Atoi(s)
},
"parseInt64": func(s string) (int64, error) {
return strconv.ParseInt(s, 10, 64)
},
"parsePlatform": func(s string) (accounts.Platform, error) {
return accounts.NewPlatform(s)
},
// arithmetic
"addInt": func(a, b int) int {
return a + b
},
@@ -81,6 +110,15 @@ func NewServer(
"multInt": func(a, b int) int {
return a * b
},
// json
"prettyPrintJSON": func(j json.RawMessage) string {
b, err := json.MarshalIndent(j, " ", "")
if err != nil {
return string(j)
}
return string(b)
},
}
},
),
@@ -88,39 +126,74 @@ func NewServer(
accts: accts,
etsy: etsy,
auth: auth,
authMiddleware: middleware.NewAuth(
auth,
newLoginURL,
accts,
),
}
// api routes
withAuth := func(fn response.HandlerFunc) response.HandlerFunc {
return s.authMiddleware.AuthenticateAndAddIdentity(fn)
}
mux.Handle("GET /login", response.Handler(s.loginPage))
mux.Handle("GET /login/callback", response.Handler(s.loginCallback))
mux.Handle("GET /logout", response.Handler(s.logoutPage))
mux.Handle("POST /accounts", response.Handler(s.authenticateAndAddIdentity(s.createAccount)))
// login
// TODO: eliminate once no longer used.
mux.HandleFunc("POST /login", response.Handler(s.login))
mux.Handle("GET /login", s.loginPage)
mux.Handle("GET /login/callback", s.loginCallback)
mux.Handle("GET /logout", s.logoutPage)
// /accounts
mux.Handle("POST /accounts", withAuth(s.createAccount))
mux.Handle("POST /accounts/{acctID}/inventory/sync-groups/draft/listings", withAuth(s.createSyncGroupListingDraft))
mux.Handle("PUT /accounts/{acctID}/inventory/sync-groups/draft/listings/{orderIndex}/shop", withAuth(s.setShopInSyncGroupListingDraft))
mux.Handle("PUT /accounts/{acctID}/inventory/sync-groups/draft/listings/{orderIndex}/listing", withAuth(s.setListingInSyncGroupListingDraft))
mux.Handle("DELETE /accounts/{acctID}/inventory/sync-groups/draft/listings/{orderIndex}", withAuth(s.deleteSyncGroupListingDraft))
mux.Handle("POST /accounts/{acctID}/inventory/sync-groups", withAuth(s.saveNewSyncGroup))
// webpage content
// non-html content: scripts, styles, images, etc
scfs := http.FileServer(http.Dir(contentDir + "/scripts"))
mux.Handle("GET /scripts/", http.StripPrefix("/scripts", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
mux.Mux.Handle("GET /scripts/", http.StripPrefix("/scripts", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/javascript")
if path.Ext(r.URL.Path) == ".gz" {
w.Header().Set("Content-Encoding", "gzip")
}
scfs.ServeHTTP(w, r)
})))
mux.Handle("GET /styles/", http.StripPrefix("/styles", http.FileServer(http.Dir(contentDir+"/styles"))))
mux.Mux.Handle("GET /styles/", http.StripPrefix("/styles", http.FileServer(http.Dir(contentDir+"/styles"))))
// webpages
// html
// all non-authenticated webpages
mux.HandleFunc("GET /{$}", response.Handler(s.addIdentity(s.serveTemplates)))
// all authenticated webpages
mux.HandleFunc("GET /", response.Handler(s.authenticateAndAddIdentity(s.serveTemplates)))
s.Handler = mux
// non-authenticated
mux.Handle("GET /{$}", s.authMiddleware.AddIdentity(s.serveTemplates))
// authenticated
mux.Handle("GET /", withAuth(s.serveTemplates))
return s
}
func mapConstantErrorsToHTTPErrors(err error) error {
cerr := err
for cerr != nil {
switch cerr {
case consts.ErrNotFound:
return response.NotFound()
case consts.ErrConflict:
return response.Conflict()
}
uerr, ok := cerr.(interface {
Unwrap() error
})
if !ok {
return err
}
cerr = uerr.Unwrap()
}
return err
}