From 2b10f05ec07be9c4dd4a14c119db73f3ab795c58 Mon Sep 17 00:00:00 2001 From: Tal Avital Date: Wed, 5 Feb 2025 15:36:02 +0200 Subject: [PATCH] add support to taboola user id module --- adapters/taboola/taboola.go | 45 +++++++++--- adapters/taboola/taboola_test.go | 119 ++++++++++++++++++++++++++++--- 2 files changed, 145 insertions(+), 19 deletions(-) diff --git a/adapters/taboola/taboola.go b/adapters/taboola/taboola.go index 9d950bef2cb..8a15889a28b 100644 --- a/adapters/taboola/taboola.go +++ b/adapters/taboola/taboola.go @@ -43,7 +43,6 @@ func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server co } func (a *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { - var requests []*adapters.RequestData taboolaRequests, errs := createTaboolaRequests(request) @@ -121,7 +120,7 @@ func (a *adapter) buildRequest(request *openrtb2.BidRequest) (*adapters.RequestD DISPLAY_ENDPOINT_PREFIX = "display" ) - //set MediaType based on first imp + // set MediaType based on first imp var mediaType string if request.Imp[0].Banner != nil { mediaType = DISPLAY_ENDPOINT_PREFIX @@ -163,6 +162,17 @@ func createTaboolaRequests(request *openrtb2.BidRequest) (taboolaRequests []*ope var errs []error var taboolaExt openrtb_ext.ImpExtTaboola + + // user ID extraction logic - checking user.ext.eids for source="taboola.com" + if userID, err := findTaboolaUserId(modifiedRequest.User); err == nil && userID != "" { + if modifiedRequest.User == nil { + modifiedRequest.User = &openrtb2.User{} + } + modifiedRequest.User.BuyerUID = userID + } else if err != nil { + errs = append(errs, err) + } + for i := 0; i < len(modifiedRequest.Imp); i++ { imp := modifiedRequest.Imp[i] @@ -180,7 +190,6 @@ func createTaboolaRequests(request *openrtb2.BidRequest) (taboolaRequests []*ope if len(taboolaExt.TagID) < 1 { tagId = taboolaExt.TagId } - imp.TagID = tagId modifiedRequest.Imp[i] = imp @@ -200,13 +209,11 @@ func createTaboolaRequests(request *openrtb2.BidRequest) (taboolaRequests []*ope } else if modifiedRequest.Imp[i].Native != nil { nativeImp = append(nativeImp, modifiedRequest.Imp[i]) } - } publisher := &openrtb2.Publisher{ ID: taboolaExt.PublisherId, } - if modifiedRequest.Site == nil { newSite := &openrtb2.Site{ ID: taboolaExt.PublisherId, @@ -227,7 +234,6 @@ func createTaboolaRequests(request *openrtb2.BidRequest) (taboolaRequests []*ope if taboolaExt.BCat != nil { modifiedRequest.BCat = taboolaExt.BCat } - if taboolaExt.BAdv != nil { modifiedRequest.BAdv = taboolaExt.BAdv } @@ -243,7 +249,6 @@ func createTaboolaRequests(request *openrtb2.BidRequest) (taboolaRequests []*ope taboolaRequests = append(taboolaRequests, overrideBidRequestImp(&modifiedRequest, nativeImp)) taboolaRequests = append(taboolaRequests, overrideBidRequestImp(&modifiedRequest, bannerImp)) - return taboolaRequests, errs } @@ -251,13 +256,11 @@ func makeRequestExt(pageType string) (json.RawMessage, error) { requestExt := &RequestExt{ PageType: pageType, } - requestExtJson, err := json.Marshal(requestExt) if err != nil { return nil, fmt.Errorf("could not marshal %s, err: %s", requestExt, err) } return requestExtJson, nil - } func getMediaType(impID string, imps []openrtb2.Imp) (openrtb_ext.BidType, error) { @@ -270,7 +273,6 @@ func getMediaType(impID string, imps []openrtb2.Imp) (openrtb_ext.BidType, error } } } - return "", &errortypes.BadInput{ Message: fmt.Sprintf("Failed to find banner/native impression \"%s\" ", impID), } @@ -299,3 +301,26 @@ func resolveMacros(bid *openrtb2.Bid) { bid.AdM = strings.Replace(bid.AdM, "${AUCTION_PRICE}", price, -1) } } + +// findTaboolaUserId attempts to read user.ext.eids (openrtb2.EID) and locate the one with source="taboola.com". +// If found, returns the ID. If user is nil, or no eids, or no taboola.com found, returns empty string. +func findTaboolaUserId(user *openrtb2.User) (string, error) { + if user == nil || user.Ext == nil { + return "", nil + } + + var userExt struct { + Eids []openrtb2.EID `json:"eids,omitempty"` + } + + if err := json.Unmarshal(user.Ext, &userExt); err != nil { + return "", fmt.Errorf("error parsing user.ext eids: %v", err) + } + + for _, eid := range userExt.Eids { + if strings.EqualFold(eid.Source, "taboola.com") && len(eid.UIDs) > 0 { + return eid.UIDs[0].ID, nil + } + } + return "", nil +} diff --git a/adapters/taboola/taboola_test.go b/adapters/taboola/taboola_test.go index bd674440150..12db22fd85d 100644 --- a/adapters/taboola/taboola_test.go +++ b/adapters/taboola/taboola_test.go @@ -1,8 +1,10 @@ package taboola import ( + "encoding/json" "testing" + "github.com/prebid/openrtb/v20/openrtb2" "github.com/prebid/prebid-server/v2/adapters/adapterstest" "github.com/prebid/prebid-server/v2/config" "github.com/prebid/prebid-server/v2/openrtb_ext" @@ -10,25 +12,124 @@ import ( ) func TestJsonSamples(t *testing.T) { - bidder, buildErr := Builder(openrtb_ext.BidderTaboola, config.Adapter{ - Endpoint: "http://{{.MediaType}}.whatever.com/{{.GvlID}}/{{.PublisherID}}"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 12, DataCenter: "2"}) - + bidder, buildErr := Builder( + openrtb_ext.BidderTaboola, + config.Adapter{ + Endpoint: "http://{{.MediaType}}.whatever.com/{{.GvlID}}/{{.PublisherID}}", + }, + config.Server{ExternalUrl: "http://hosturl.com", GvlID: 12, DataCenter: "2"}, + ) if buildErr != nil { t.Fatalf("Builder returned unexpected error %v", buildErr) } - adapterstest.RunJSONBidderTest(t, "taboolatest", bidder) } +// TestEmptyExternalUrl checks if gvlID remains empty when GvlID=0 func TestEmptyExternalUrl(t *testing.T) { - bidder, buildErr := Builder(openrtb_ext.BidderTaboola, config.Adapter{ - Endpoint: "http://whatever.com"}, config.Server{}) - + bidder, buildErr := Builder( + openrtb_ext.BidderTaboola, + config.Adapter{Endpoint: "http://whatever.com"}, + config.Server{}, + ) if buildErr != nil { t.Fatalf("Builder returned unexpected error %v", buildErr) } - bidderTaboola := bidder.(*adapter) + assert.Equal(t, "", bidderTaboola.gvlID, "Expected empty gvlID when GvlID=0") +} + +// TestNoEids ensures that if user.ext has no taboola.com eids, we don't set BuyerUID. +func TestNoEids(t *testing.T) { + bidder, buildErr := Builder( + openrtb_ext.BidderTaboola, + config.Adapter{Endpoint: "http://whatever.com"}, + config.Server{}, + ) + assert.NoError(t, buildErr) + w, h := int64(300), int64(250) + + // Minimal request with no user or user.ext + req := &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{ + { + ID: "imp1", + Banner: &openrtb2.Banner{W: &w, H: &h}, + Ext: json.RawMessage(`{"bidder":{"tagid": "example-tag"}}`), + }, + }, + // No user at all -> no eids + } + + // MakeRequests + requests, errs := bidder.MakeRequests(req, nil) + assert.Empty(t, errs, "Expected no errors") + assert.NotEmpty(t, requests, "Should produce at least one request") + + // Parse the request body to confirm BuyerUID is not set + for _, r := range requests { + var parsed openrtb2.BidRequest + err := json.Unmarshal(r.Body, &parsed) + assert.NoError(t, err) - assert.Equal(t, "", bidderTaboola.gvlID) + if parsed.User != nil { + assert.Empty(t, parsed.User.BuyerUID, "Expected BuyerUID to remain empty when no taboola.com eids present") + } + } +} + +// TestWithTaboolaEid ensures that if user.ext.eids includes source=taboola.com, +// we set user.BuyerUID to that ID. +func TestWithTaboolaEid(t *testing.T) { + bidder, buildErr := Builder( + openrtb_ext.BidderTaboola, + config.Adapter{Endpoint: "http://whatever.com"}, + config.Server{}, + ) + assert.NoError(t, buildErr) + + // Create user.ext that has an eid with source="taboola.com" + eidsJSON := `{ + "eids": [ + { + "source": "taboola.com", + "uids": [{"id": "taboola-user-123"}] + }, + { + "source": "other.com", + "uids": [{"id": "not-used"}] + } + ] + }` + userExt := json.RawMessage(eidsJSON) + w, h := int64(300), int64(250) + req := &openrtb2.BidRequest{ + Imp: []openrtb2.Imp{ + { + ID: "imp1", + Banner: &openrtb2.Banner{W: &w, H: &h}, + Ext: json.RawMessage(`{"bidder":{"tagid": "example-tag"}}`), + }, + }, + User: &openrtb2.User{ + Ext: userExt, + }, + } + + // MakeRequests + requests, errs := bidder.MakeRequests(req, nil) + assert.Empty(t, errs, "Expected no errors with valid eids") + assert.NotEmpty(t, requests, "Should produce at least one request") + + // Check that user.BuyerUID was set to "taboola-user-123" + for _, r := range requests { + var parsed openrtb2.BidRequest + err := json.Unmarshal(r.Body, &parsed) + assert.NoError(t, err) + + if parsed.User != nil { + assert.Equal(t, "taboola-user-123", parsed.User.BuyerUID, + "Expected BuyerUID to be set from taboola.com eids ID") + } + } }