package etsy import ( "encoding/json" "fmt" "strconv" "time" "github.com/gin-gonic/gin" "ruben/inventory2/domains/platforms/etsy" "ruben/inventory2/domains/raw_events" "ruben/inventory2/logging" "ruben/inventory2/server/response" ) type ( Config struct { OAuthRedirectURIWithAcctIDParam string } ) func Routes( r *gin.RouterGroup, logger *logging.Logger, db *raw_events.Store, platform *etsy.Platform, cfg Config, ) { h := webhooks{ log: logger, cfg: cfg, db: db, etsy: platform, } r.POST("/test", response.Handler(h.test)) r.GET(h.cfg.OAuthRedirectURIWithAcctIDParam, response.Handler(h.redirectURI)) r.GET("/:acctID/new-account-link", response.Handler(h.newAccountLink)) } type ( webhooks struct { log *logging.Logger cfg Config db *raw_events.Store etsy *etsy.Platform } ) // POST /test func (h webhooks) test(c *gin.Context) (response.Response, error) { r := c.Request var body json.RawMessage if err := json.NewDecoder(r.Body).Decode(&body); err != nil { return nil, response.Errorf("failed to decode body as json: %w", err) } ts := time.Now().UTC() storeID := "test-store-id" var payloadObject struct { StoreID string } if err := json.Unmarshal(body, &payloadObject); err == nil && payloadObject.StoreID != "" { storeID = payloadObject.StoreID } err := h.db.Save(r.Context(), &raw_events.Event{ Platform: "etsy", StoreID: storeID, EventID: fmt.Sprint(ts.Unix()), EventTimestamp: ts, Payload: body, }) if err != nil { return nil, response.Errorf("error occurred saving the body as the event payload: %w", err) } return response.Status(201), nil } // GET h.cfg.OAuthRedirectURIWithAcctIDParam func (h webhooks) redirectURI(c *gin.Context) (response.Response, error) { r := c.Request // get account id for the request acctID, err := strconv.ParseInt(c.Param("acctID"), 10, 64) if err != nil || acctID <= 0 { return nil, response.NotFound() } ctx := r.Context() q := r.URL.Query() state := q.Get("state") // handle failed, potentially non-consenting, request if errCode := q.Get("error"); errCode != "" { errDesc := q.Get("error_description") errURI := q.Get("error_uri") fmt.Printf( "error in obtaining an OAuth Token: error=%s, error_desc=%s, error_uri=%s, account_id=%d\n", errCode, errDesc, errURI, acctID, ) h.etsy.InvalidateState(ctx, state) return response.Status(200), nil } // validate the state to prevent CSRF attacks ok, err := h.etsy.HandleNewAuthCode(ctx, acctID, state, q.Get("code")) if err != nil { h.log.Error("failed to handle new auth code", "error", err) return nil, response.Forbidden() } if !ok { return nil, response.Forbidden() } // redirect to the user's account page return response.SeeOther(fmt.Sprintf("/accounts/%d", acctID)), nil } // GET /:acctID/new-account-link func (h webhooks) newAccountLink(c *gin.Context) (response.Response, error) { r := c.Request acctIDStr := c.Param("acctID") acctID, err := strconv.ParseInt(acctIDStr, 10, 64) if err != nil { return nil, response.NotFound().Msgf("account %s not found", acctIDStr) } u, err := h.etsy.GenerateConnectionURLForNewAccount(r.Context(), acctID) if err != nil { return nil, fmt.Errorf("failed to generate url for account %d: %w", acctID, err) } return response.TemporaryRedirect(u.String()), nil }