Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions customerio/event.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"bytes"
"context"
"crypto/sha1"
"fmt"
"net/http"
"time"

Expand All @@ -22,10 +23,10 @@ type Event struct {
Data any `json:"data"`
}

// SetDeduplicationID generates ULID that's used for deduplication and using the provided time and the first 10 bytes of the sha1 hashed deduplication ID
// SetDeduplicationID generates ULID that's used for deduplication and using the provided time and the first 10 bytes of the sha1 hashed event name + deduplication ID
// Returns an error if time is before epoch or deduplicationID is empty
func (e *Event) SetDeduplicationID(time *time.Time, deduplicationID string) (err error) {
e.ID, err = CreateUlid(time, deduplicationID)
e.ID, err = CreateUlid(time, fmt.Sprintf("%s:%s", e.Name, deduplicationID))
return
}

Expand All @@ -48,6 +49,8 @@ func (c *Client) SendEvent(ctx context.Context, userID string, event *Event) err
c.trackAPIAuthMutator(),
}

c.logger.WithField("userId", userID).WithField("url", url).Debugf("sending %s event", event.Name)
Comment thread
darinkrauss marked this conversation as resolved.

if err := c.trackClient.RequestDataWithHTTPClient(ctx, http.MethodPost, url, mutators, event, nil, nil, c.httpClient); err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion customerio/work/event/processor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ var _ = Describe("Processor", func() {
}),
}

id, err := customerio.CreateUlid(&deduplicationTime, deduplicationID)
id, err := customerio.CreateUlid(&deduplicationTime, "data_source_state_changed"+":"+deduplicationID)
Expect(err).ToNot(HaveOccurred())

trackAPIResponses.AddResponse(
Expand Down
22 changes: 12 additions & 10 deletions oura/jotform/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,12 +85,8 @@ func (c *defaultClient) ListFormSubmissions(ctx context.Context, formID string,

url = c.client.AppendURLQuery(url, query)

mutators := []request.RequestMutator{
request.NewHeaderMutator("APIKEY", c.config.APIKey),
}

var response FormSubmissionsResponse
if err := c.client.RequestDataWithHTTPClient(ctx, http.MethodGet, url, mutators, nil, &response, nil, c.httpClient); err != nil {
if err := c.client.RequestDataWithHTTPClient(ctx, http.MethodGet, url, c.authMutators(), nil, &response, nil, c.httpClient); err != nil {
return nil, err
}

Expand All @@ -105,12 +101,8 @@ func (c *defaultClient) ListFormSubmissions(ctx context.Context, formID string,
func (c *defaultClient) GetSubmission(ctx context.Context, submissionID string) (*SubmissionResponse, error) {
url := c.client.ConstructURL("v1", "submission", submissionID)

mutators := []request.RequestMutator{
request.NewHeaderMutator("APIKEY", c.config.APIKey),
}

var response SubmissionResponse
if err := c.client.RequestDataWithHTTPClient(ctx, http.MethodGet, url, mutators, nil, &response, nil, c.httpClient); err != nil {
if err := c.client.RequestDataWithHTTPClient(ctx, http.MethodGet, url, c.authMutators(), nil, &response, nil, c.httpClient); err != nil {
return nil, err
}

Expand All @@ -121,3 +113,13 @@ func (c *defaultClient) GetSubmission(ctx context.Context, submissionID string)

return &response, nil
}

func (c *defaultClient) authMutators() []request.RequestMutator {
mutators := []request.RequestMutator{
request.NewHeaderMutator("APIKEY", c.config.APIKey),
}
if c.config.TeamID != "" {
mutators = append(mutators, request.NewHeaderMutator("jf-team-id", c.config.TeamID))
}
return mutators
}
23 changes: 20 additions & 3 deletions oura/jotform/processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,11 @@ type SubmissionProcessor struct {
}

type Config struct {
Enabled bool `envconfig:"TIDEPOOL_OURA_JOTFORM_ENABLED"`
BaseURL string `envconfig:"TIDEPOOL_OURA_JOTFORM_BASE_URL" default:"https://api.jotform.com"`
APIKey string `envconfig:"TIDEPOOL_OURA_JOTFORM_API_KEY"`
FormID string `envconfig:"TIDEPOOL_OURA_JOTFORM_FORM_ID"`
TeamID string `envconfig:"TIDEPOOL_OURA_JOTFORM_TEAM_ID"`
}

func NewSubmissionProcessor(config Config, logger log.Logger, consentService consent.Service, customerIOClient *customerio.Client, userClient user.Client, shopifyClient shopify.Client, submissionStore store.Store) (*SubmissionProcessor, error) {
Expand All @@ -73,6 +75,12 @@ func NewSubmissionProcessor(config Config, logger log.Logger, consentService con
}

func (s *SubmissionProcessor) Reconcile(ctx context.Context, lastSubmissionID string) (ReconcileResult, error) {
if !s.config.Enabled {
s.logger.Debug("jotform reconcile was called, but jotform integration is not enabled")
return ReconcileResult{
LastProcessedID: lastSubmissionID,
}, nil
}
return s.reconcile(ctx, s.config.FormID, lastSubmissionID)
}

Expand Down Expand Up @@ -124,6 +132,11 @@ func (s *SubmissionProcessor) reconcile(ctx context.Context, formID string, last
}

func (s *SubmissionProcessor) ProcessSubmission(ctx context.Context, submissionID string) error {
if !s.config.Enabled {
s.logger.Debug("jotform process submission was called, but jotform integration is not enabled")
return nil
}

submission, err := s.jotformClient.GetSubmission(ctx, submissionID)
if err != nil {
return errors.Wrap(err, "failed to get submission")
Expand Down Expand Up @@ -187,24 +200,28 @@ func (s *SubmissionProcessor) validateUser(ctx context.Context, submissionID str
logger.Info("submission has no user id")
return nil, nil
}
logger = logger.WithField("userId", userID)

participantID := answers.GetAnswerTextByName(ParticipantIDField)
if participantID == "" {
logger.Info("submission has no participant id")
return nil, nil
}
logger = logger.WithField("submissionParticipantId", participantID)

customer, err := s.customerIOClient.GetCustomer(ctx, userID, customerio.IDTypeUserID)
if err != nil {
return nil, errors.Wrapf(err, "unable to get customer with id %s", userID)
}

if customer == nil {
logger.Warnf("customer not found for user with id %s", userID)
logger.Warnf("no matching customer found for user id")
return nil, nil
}
if customer.OuraParticipantID != participantID {
logger.Warnf("participant id mismatch for user with id %s", userID)
logger.
WithField("customerParticipantId", customer.OuraParticipantID).
Warnf("submission participant id does not match customer participant id")
return nil, nil
}

Expand All @@ -213,7 +230,7 @@ func (s *SubmissionProcessor) validateUser(ctx context.Context, submissionID str
return nil, errors.Wrap(err, "unable to get user")
}
if usr == nil {
logger.Warnf("participant id mismatch for user with id %s", userID)
logger.Warnf("user not found")
return nil, nil
}

Expand Down
2 changes: 2 additions & 0 deletions oura/jotform/processor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ var _ = Describe("SubmissionProcessor", func() {
jotformConfig := jotform.Config{
BaseURL: jotformServer.URL,
FormID: formID,
Enabled: true,
TeamID: "test-team",
}

appAPIResponses = ouraTest.NewStubResponses()
Expand Down
14 changes: 8 additions & 6 deletions oura/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@ func (p *Provider) OnCreate(ctx context.Context, providerSession *auth.ProviderS
if err != nil {
return errors.Wrap(err, "unable to prepare data source")
}
if err = p.connectDataSourceToProviderSession(ctx, providerSession, dataSrc); err != nil {
dataSrc, err = p.connectDataSourceToProviderSession(ctx, providerSession, dataSrc)
if err != nil {
return errors.Wrap(err, "unable to connect data source")
}
if err = p.createDataSetupWork(ctx, dataSrc); err != nil {
Expand Down Expand Up @@ -218,13 +219,13 @@ func (p *Provider) prepareDataSourceForProviderSession(ctx context.Context, prov
return dataSrc, nil
}

func (p *Provider) connectDataSourceToProviderSession(ctx context.Context, providerSession *auth.ProviderSession, dataSrc *dataSource.Source) error {
func (p *Provider) connectDataSourceToProviderSession(ctx context.Context, providerSession *auth.ProviderSession, dataSrc *dataSource.Source) (*dataSource.Source, error) {
providerSessionUpdate := &auth.ProviderSessionUpdate{
OAuthToken: providerSession.OAuthToken,
ExternalID: providerSession.ExternalID,
}
if _, err := p.providerSessionClient.UpdateProviderSession(ctx, providerSession.ID, providerSessionUpdate); err != nil {
return errors.Wrap(err, "unable to update provider session")
return nil, errors.Wrap(err, "unable to update provider session")
}

dataSrcUpdate := &dataSource.Update{
Expand All @@ -233,11 +234,12 @@ func (p *Provider) connectDataSourceToProviderSession(ctx context.Context, provi
State: pointer.FromString(dataSource.StateConnected),
DataSetIDs: dataSrc.DataSetIDs,
}
if _, err := p.dataSourceClient.Update(ctx, *dataSrc.ID, nil, dataSrcUpdate); err != nil {
return errors.Wrap(err, "unable to update data source")
dataSrc, err := p.dataSourceClient.Update(ctx, *dataSrc.ID, nil, dataSrcUpdate)
if err != nil {
return nil, errors.Wrap(err, "unable to update data source")
}

return nil
return dataSrc, nil
}

func (p *Provider) disconnectDataSourcesFromProviderSession(ctx context.Context, providerSession *auth.ProviderSession) error {
Expand Down
10 changes: 7 additions & 3 deletions oura/shopify/client/order.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package client
import (
"context"
"fmt"
"maps"
"slices"
"strings"
"time"

Expand All @@ -18,7 +20,7 @@ query GetOrder($identifier: OrderIdentifierInput!) {
createdAt
updatedAt
discountCode
lineItems {
lineItems(first: 10) {
nodes {
product {
id
Expand Down Expand Up @@ -53,6 +55,7 @@ func (c *defaultClient) GetOrderSummary(ctx context.Context, orderID string) (*s

order := resp.GetOrderByIdentifier()
summary := shopify.OrderSummary{
GID: orderID,
CreatedTime: order.CreatedAt,
DiscountCode: pointer.Default(order.GetDiscountCode(), ""),
UpdatedTime: order.UpdatedAt,
Expand All @@ -66,6 +69,7 @@ func (c *defaultClient) GetOrderSummary(ctx context.Context, orderID string) (*s
summary.OrderedProductIDs = append(summary.OrderedProductIDs, id)
}

deliveredProducts := map[string]struct{}{}
for _, fulfillment := range order.Fulfillments {
if fulfillment == nil {
continue
Expand All @@ -83,10 +87,10 @@ func (c *defaultClient) GetOrderSummary(ctx context.Context, orderID string) (*s
continue
}
id := strings.TrimPrefix(lineItem.GetLineItem().GetProduct().GetId(), shopify.ProductGIDPrefix)
summary.DeliveredProductIDs = append(summary.DeliveredProductIDs, id)
deliveredProducts[id] = struct{}{}
}
}

summary.DeliveredProductIDs = slices.Collect(maps.Keys(deliveredProducts))
return &summary, nil
}

Expand Down
4 changes: 2 additions & 2 deletions oura/shopify/discount.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ const (
//OuraSizingKitProductID = "9122899853526"
//OuraRingProductID = "9112952373462"

OuraSizingKitProductID = "15536573219203" // Todd's test gstore
OuraSizingKitProductID = "9280563445974" // Dummy Sizing Kit
OuraSizingKitDiscountCodeTitle = "Oura Sizing Kit Discount Code"

OuraRingProductID = "15496765964675" // Todd's test store
OuraRingProductID = "9280563708118" // Dummy Oura ring
OuraRingDiscountCodeTitle = "Oura Ring Discount Code"

DiscountCodeLength = 12
Expand Down
2 changes: 1 addition & 1 deletion oura/shopify/generated/generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 6 additions & 2 deletions oura/shopify/processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,12 @@ func (p *OrderProcessor) ProcessFulfillment(ctx context.Context, event Fulfillme
orderGID := GetOrderGID(event.OrderID)
logger := p.logger.WithField("orderGID", orderGID)

if event.Status != "success" {
logger.WithField("status", event.Status).Info("ignoring fulfillment event")
return nil
}
if event.ShipmentStatus == nil || !strings.EqualFold(*event.ShipmentStatus, "delivered") {
logger.Info("ignoring non-delivery fulfillment event")
logger.WithField("shipmentStatus", event.ShipmentStatus).Info("ignoring fulfillment event")
return nil
}

Expand All @@ -174,7 +178,7 @@ func (p *OrderProcessor) processDeliveredOrder(ctx context.Context, order OrderS
if event, err := p.store.GetShopifyOrderEvent(ctx, order.GID, store.OrderEventTypeDelivered); err != nil {
return errors.Wrap(err, "unable to retrieve shopify order event")
} else if event != nil {
logger.Info("ignoring order create event because it was already processed")
logger.Info("ignoring order delivered event because it was already processed")
return nil
}

Expand Down
6 changes: 4 additions & 2 deletions oura/shopify/processor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ var _ = Describe("OrderProcessor", func() {
event := shopify.FulfillmentEvent{
ID: 9876543,
CreatedAt: time.Now(),
Status: "success",
ShipmentStatus: pointer.FromAny("delivered"),
OrderID: rand.Int63n(999999999999),
}
Expand All @@ -112,7 +113,7 @@ var _ = Describe("OrderProcessor", func() {
DiscountCode: sizingKitDiscountCode,
}

deduplicationID, err := customerio.CreateUlid(&orderSummary.CreatedTime, orderSummary.GID)
deduplicationID, err := customerio.CreateUlid(&orderSummary.CreatedTime, "oura_sizing_kit_delivered"+":"+orderSummary.GID)
Expect(err).ToNot(HaveOccurred())

shopifyClnt.EXPECT().
Expand Down Expand Up @@ -178,6 +179,7 @@ var _ = Describe("OrderProcessor", func() {
event := shopify.FulfillmentEvent{
ID: 9876543,
CreatedAt: time.Now(),
Status: "success",
ShipmentStatus: pointer.FromAny("delivered"),
OrderID: rand.Int63n(999999999999),
}
Expand All @@ -190,7 +192,7 @@ var _ = Describe("OrderProcessor", func() {
DiscountCode: discountCode,
}

deduplicationID, err := customerio.CreateUlid(&orderSummary.CreatedTime, orderID)
deduplicationID, err := customerio.CreateUlid(&orderSummary.CreatedTime, "oura_ring_delivered"+":"+orderID)
Expect(err).ToNot(HaveOccurred())

dataSourceClient.EXPECT().
Expand Down