Files
inventory-plus-plus/internal/server/api/accounts/router.go
T

225 lines
6.8 KiB
Go

package accounts
import (
"errors"
"fmt"
"strconv"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
"ruben/inventory2/internal/consts"
"ruben/inventory2/internal/domains/accounts"
"ruben/inventory2/internal/logging"
"ruben/inventory2/internal/server/auth"
"ruben/inventory2/internal/server/response"
"ruben/inventory2/internal/server/sse"
)
type accountSubrouter struct {
log *logging.Logger
accts *accounts.Store
}
func Routes(
r *gin.RouterGroup,
logger *logging.Logger,
accts *accounts.Store,
pub *sse.UpdateNotificationPublisher,
) {
as := &accountSubrouter{
log: logger,
accts: accts,
}
r.POST("", response.Handler(as.createAccount))
r.PUT("/:acctID/platforms/:platform/order-index", pub.Publish("/:acctID/platforms"), response.Handler(as.setOrderOfPlatformOnAccountPage))
syncGroups := r.Group("/:acctID/inventory/sync-groups")
syncGroups.POST("", pub.Publish("/:acctID/inventory/sync-groups"), response.Handler(as.saveNewSyncGroup))
draftListings := syncGroups.Group("/draft/listings", pub.Publish("/:acctID/inventory/sync-groups/draft/listings"))
draftListings.POST("", response.Handler(as.createSyncGroupListingDraft))
draftListings.PUT("/:orderIndex/shop", response.Handler(as.setShopInSyncGroupListingDraft))
draftListings.PUT("/:orderIndex/listing", response.Handler(as.setListingInSyncGroupListingDraft))
draftListings.DELETE("/:orderIndex", response.Handler(as.deleteSyncGroupListingDraft))
}
// POST /
func (s *accountSubrouter) createAccount(c *gin.Context) (response.Response, error) {
r := c.Request
ctx := r.Context()
// TODO: get email from the user's account profile (how?) - will need to flesh out the account creation process later on
email := uuid.NewString() + "@example.com"
userID := auth.GetIdentity(ctx).User.UserID
_, 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.StatusCreated().
// force a reload to ensure an sse connection is made.
// user should automatically be redirected to the appropriate page based on their current location and/or login/account statuses.
HXRefresh("true"), nil
}
// POST /:acctID/inventory/sync-groups/draft/listings
func (s *accountSubrouter) createSyncGroupListingDraft(c *gin.Context) (response.Response, error) {
r := c.Request
ctx := r.Context()
acctID := auth.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.StatusCreated(), nil
}
// PUT /: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 := auth.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.StatusOK(), nil
}
// PUT /: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 := auth.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.StatusOK(), nil
}
// DELETE /:acctID/inventory/sync-groups/draft/listings/{orderIndex}
func (s *accountSubrouter) deleteSyncGroupListingDraft(c *gin.Context) (response.Response, error) {
r := c.Request
ctx := r.Context()
acctID := auth.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.StatusOK(), nil
}
// POST /:acctID/inventory/sync-groups
func (s *accountSubrouter) saveNewSyncGroup(c *gin.Context) (response.Response, error) {
r := c.Request
ctx := r.Context()
acctID := auth.GetIdentity(ctx).Account.AccountID
if _, err := s.accts.SaveNewSyncGroup(ctx, acctID); err != nil {
return nil, response.Errorf("failed to save new sync group: %w", response.ErrorFromConstant(err))
}
return response.StatusCreated(), 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
}
func (s *accountSubrouter) setOrderOfPlatformOnAccountPage(c *gin.Context) (response.Response, error) {
acctID := auth.GetIdentity(c).Account.AccountID
var orderIndex int
if v, ok := c.GetPostForm("order-index"); !ok {
return nil, response.BadRequest().
Msg("no order-index provided")
} else if i, err := strconv.Atoi(v); err != nil {
return nil, response.BadRequest().
Msgf("order-index must be a non-negative integer: %s", v)
} else if i < 0 {
return nil, response.BadRequest().
Msgf("order-index must be a non-negative integer: %s", v)
} else {
orderIndex = i
}
var platform accounts.Platform
if v := c.Param("platform"); v == "" {
return nil, response.BadRequest().
Msg("no platform provided")
} else if p, err := accounts.NewPlatform(v); err != nil {
return nil, response.BadRequest().
Wrap(err).
Msgf("unrecognized platform: %v", v)
} else {
platform = p
}
if err := s.accts.SetOrderOfPlatformOnAccountPage(c, acctID, platform, orderIndex); err != nil {
return nil, fmt.Errorf("failed to save record: %w", err)
}
return response.Status(200), nil
}