Files
inventory-plus-plus/internal/server/api/accounts/router.go
T
2026-01-13 22:48:09 -07:00

200 lines
6.0 KiB
Go

package accounts
import (
"errors"
"fmt"
"net/http"
"ruben/inventory2/internal/consts"
"ruben/inventory2/internal/domains/accounts"
"ruben/inventory2/internal/logging"
"ruben/inventory2/internal/server/middleware"
"ruben/inventory2/internal/server/response"
"strconv"
"github.com/gin-gonic/gin"
)
type accountSubrouter struct {
log *logging.Logger
accts *accounts.Store
}
func Routes(
r *gin.RouterGroup,
logger *logging.Logger,
accts *accounts.Store,
authMiddleware *middleware.Auth,
) {
as := &accountSubrouter{
log: logger,
accts: accts,
}
withAuth := func(fn response.HandlerFunc) gin.HandlerFunc {
return response.Handler(authMiddleware.AuthenticateAndAddIdentity(fn))
}
r.POST("/:acctID/inventory/sync-groups/draft/listings", withAuth(as.createSyncGroupListingDraft))
r.PUT("/:acctID/inventory/sync-groups/draft/listings/:orderIndex/shop", withAuth(as.setShopInSyncGroupListingDraft))
r.PUT("/:acctID/inventory/sync-groups/draft/listings/:orderIndex/listing", withAuth(as.setListingInSyncGroupListingDraft))
r.DELETE("/:acctID/inventory/sync-groups/draft/listings/:orderIndex", withAuth(as.deleteSyncGroupListingDraft))
r.POST("/:acctID/inventory/sync-groups", withAuth(as.saveNewSyncGroup))
}
// POST /api/accounts
func (s *accountSubrouter) createAccount(c *gin.Context) (response.Response, error) {
r := c.Request
ctx := r.Context()
email := r.FormValue("email")
if email == "" {
return nil, response.BadRequest().Msg("no email provided")
}
userID := middleware.GetIdentity(ctx).User.UserID
acct, err := s.accts.CreateAccount(ctx, userID, email)
if err != nil {
if errors.Is(err, consts.ErrConflict) {
return nil, response.Conflict().
Msg("user already has an account")
}
return nil, response.Errorf("failed to create account: %w", err)
}
return response.SeeOther(fmt.Sprintf("/api/accounts/%d", acct.AccountID)), nil
}
// POST /api/accounts/{acctID}/inventory/sync-groups/draft/listings
func (s *accountSubrouter) createSyncGroupListingDraft(c *gin.Context) (response.Response, error) {
r := c.Request
ctx := r.Context()
acctID := middleware.GetIdentity(ctx).Account.AccountID
if _, err := s.accts.CreateSyncGroupListingDraft(ctx, acctID); err != nil {
return nil, response.Errorf("failed to create new listing draft: %w", err)
}
return response.Redirect(
http.StatusSeeOther,
fmt.Sprintf("/ui/accounts/%d/inventory/sync-groups/draft/table", acctID),
), nil
}
// PUT /api/accounts/{acctID}/inventory/sync-groups/draft/listings/{orderIndex}/shop
// @platform string
// @shopID string
func (s *accountSubrouter) setShopInSyncGroupListingDraft(c *gin.Context) (response.Response, error) {
r := c.Request
ctx := r.Context()
acctID := middleware.GetIdentity(ctx).Account.AccountID
orderIndex, err := getOrderIndexForSyncGroupListingDraftFromPath(c)
if err != nil {
return nil, err
}
platformStr := r.FormValue("platform")
platform, err := accounts.NewPlatform(platformStr)
if err != nil {
return nil, response.BadRequest().
Msgf("unrecognized platform: %s", platformStr)
}
shopID := r.FormValue("shop-id")
if shopID == "" {
return nil, response.BadRequest().
Msg("no shop-id provided")
}
if err := s.accts.SetShopInSyncGroupListingDraft(ctx, acctID, orderIndex, platform, shopID); err != nil {
return nil, response.Errorf("failed to set shop: %w", response.ErrorFromConstant(err))
}
return response.Redirect(
http.StatusSeeOther,
fmt.Sprintf("/ui/accounts/%d/inventory/sync-groups/draft/table", acctID),
), nil
}
// PUT /api/accounts/{acctID}/inventory/sync-groups/draft/listings/{orderIndex}/listing
func (s *accountSubrouter) setListingInSyncGroupListingDraft(c *gin.Context) (response.Response, error) {
r := c.Request
ctx := r.Context()
acctID := middleware.GetIdentity(ctx).Account.AccountID
orderIndex, err := getOrderIndexForSyncGroupListingDraftFromPath(c)
if err != nil {
return nil, err
}
listingID := r.FormValue("listing-id")
if listingID == "" {
return nil, response.BadRequest().
Msg("no listing-id provided")
}
if err := s.accts.SetListingInSyncGroupListingDraft(ctx, acctID, orderIndex, listingID); err != nil {
return nil, response.Errorf("failed to set listing: %w", response.ErrorFromConstant(err))
}
return response.Redirect(
http.StatusSeeOther,
fmt.Sprintf("/ui/accounts/%d/inventory/sync-groups/draft/table", acctID),
), nil
}
// DELETE /api/accounts/{acctID}/inventory/sync-groups/draft/listings/{orderIndex}
func (s *accountSubrouter) deleteSyncGroupListingDraft(c *gin.Context) (response.Response, error) {
r := c.Request
ctx := r.Context()
acctID := middleware.GetIdentity(ctx).Account.AccountID
orderIndex, err := getOrderIndexForSyncGroupListingDraftFromPath(c)
if err != nil {
return nil, err
}
if _, err := s.accts.DeleteSyncGroupListingDraft(ctx, acctID, orderIndex); err != nil {
return nil, response.Errorf("failed to delete listing: %w", response.ErrorFromConstant(err))
}
return response.Redirect(
http.StatusSeeOther,
fmt.Sprintf("/ui/accounts/%d/inventory/sync-groups/draft/table", acctID),
), nil
}
// POST /api/accounts/{acctID}/inventory/sync-groups
func (s *accountSubrouter) saveNewSyncGroup(c *gin.Context) (response.Response, error) {
r := c.Request
ctx := r.Context()
acctID := middleware.GetIdentity(ctx).Account.AccountID
grp, err := s.accts.SaveNewSyncGroup(ctx, acctID)
if err != nil {
return nil, response.Errorf("failed to save new sync group: %w", response.ErrorFromConstant(err))
}
return response.Redirect(
http.StatusSeeOther,
// TODO: template not implemented
fmt.Sprintf("/ui/accounts/%d/inventory/sync-groups/%d", acctID, grp.SyncGroupID),
), nil
}
func getOrderIndexForSyncGroupListingDraftFromPath(c *gin.Context) (int, error) {
orderIndexStr := c.Param("orderIndex")
if orderIndexStr == "" {
return 0, response.NotFound().
Msg("no orderIndex found")
}
orderIndex, err := strconv.Atoi(orderIndexStr)
if err != nil {
return 0, response.NotFound().
Msgf("invalid order index: %s", orderIndexStr)
}
return orderIndex, nil
}