Skip to content

Commit

Permalink
Taboola Adapter: support native (#2550)
Browse files Browse the repository at this point in the history
* support-native

* support-native

* support-native

* support-native

* support-native

* support-native

* support-native

* support-native

* support-native

* support-native

* support-native

* support-native

* support-native

* support-native
  • Loading branch information
ahmadlob authored Feb 13, 2023
1 parent 1fce165 commit 4109b90
Show file tree
Hide file tree
Showing 16 changed files with 638 additions and 31 deletions.
152 changes: 135 additions & 17 deletions adapters/taboola/taboola.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,45 +3,69 @@ package taboola
import (
"encoding/json"
"fmt"
"github.com/prebid/openrtb/v17/native1"
nativeResponse "github.com/prebid/openrtb/v17/native1/response"
"github.com/prebid/openrtb/v17/openrtb2"
"github.com/prebid/prebid-server/adapters"
"github.com/prebid/prebid-server/config"
"github.com/prebid/prebid-server/errortypes"
"github.com/prebid/prebid-server/macros"
"github.com/prebid/prebid-server/openrtb_ext"
"net/http"
"net/url"
"text/template"
)

type adapter struct {
endpoint string
endpoint *template.Template
hostName string
}

// Builder builds a new instance of the Foo adapter for the given bidder with the given config.
// Builder builds a new instance of Taboola adapter for the given bidder with the given config.
func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) {
endpointTemplate, err := template.New("endpointTemplate").Parse(config.Endpoint)
if err != nil {
return nil, fmt.Errorf("unable to parse endpoint url template: %v", err)
}

hostName := ""
if server.ExternalUrl != "" {
parsedUrl, err := url.Parse(server.ExternalUrl)
if err == nil && parsedUrl != nil {
hostName = parsedUrl.Host
}
}

if err != nil {
return nil, fmt.Errorf("unable to parse endpoint url template: %v", err)
}
bidder := &adapter{
endpoint: config.Endpoint,
endpoint: endpointTemplate,
hostName: hostName,
}
return bidder, nil
}

func (a *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {

taboolaRequest, errs := createTaboolaRequest(request)
var requests []*adapters.RequestData

taboolaRequests, errs := createTaboolaRequests(request)
if len(errs) > 0 {
return nil, errs
}

requestJSON, err := json.Marshal(taboolaRequest)
if err != nil {
return nil, []error{err}
}

requestData := &adapters.RequestData{
Method: "POST",
Uri: a.endpoint + "/" + taboolaRequest.Site.ID,
Body: requestJSON,
for _, taboolaRequest := range taboolaRequests {
if len(taboolaRequest.Imp) > 0 {
request, err := a.buildRequest(taboolaRequest)
if err != nil {
return nil, []error{fmt.Errorf("unable to build request %v", err)}
}
requests = append(requests, request)
}
}

return []*adapters.RequestData{requestData}, errs
return requests, errs
}

func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) {
Expand Down Expand Up @@ -79,6 +103,20 @@ func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.R
errs = append(errs, err)
continue
}
if bidType == openrtb_ext.BidTypeNative {
var nativePayload nativeResponse.Response
if err := json.Unmarshal(json.RawMessage(seatBid.Bid[i].AdM), &nativePayload); err != nil {
errs = append(errs, err)
continue
}
overrideEventTrackers(&nativePayload)
nativePayloadJson, err := json.Marshal(nativePayload)
if err != nil {
errs = append(errs, err)
continue
}
seatBid.Bid[i].AdM = string(nativePayloadJson)
}
b := &adapters.TypedBid{
Bid: &seatBid.Bid[i],
BidType: bidType,
Expand All @@ -89,8 +127,55 @@ func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.R
return bidResponse, errs
}

func createTaboolaRequest(request *openrtb2.BidRequest) (taboolaRequest *openrtb2.BidRequest, errors []error) {
func (a *adapter) buildRequest(request *openrtb2.BidRequest) (*adapters.RequestData, error) {
requestJSON, err := json.Marshal(request)
if err != nil {
return nil, err
}

const (
NATIVE_ENDPOINT_PREFIX = "native"
DISPLAY_ENDPOINT_PREFIX = "display"
)

//set MediaType based on first imp
var mediaType string
if request.Imp[0].Banner != nil {
mediaType = DISPLAY_ENDPOINT_PREFIX
} else if request.Imp[0].Native != nil {
mediaType = NATIVE_ENDPOINT_PREFIX
} else {
return nil, fmt.Errorf("unsupported media type for imp: %v", request.Imp[0])
}

url, err := a.buildEndpointURL(request.Site.ID, mediaType)
if err != nil {
return nil, err
}

requestData := &adapters.RequestData{
Method: "POST",
Uri: url,
Body: requestJSON,
}

return requestData, nil
}

// Builds endpoint url based on adapter-specific pub settings from imp.ext
func (a *adapter) buildEndpointURL(publisherId string, mediaType string) (string, error) {
endpointParams := macros.EndpointTemplateParams{PublisherID: publisherId, MediaType: mediaType, Host: a.hostName}
resolvedUrl, err := macros.ResolveMacros(a.endpoint, endpointParams)
if err != nil {
return "", err
}
return resolvedUrl, nil
}

func createTaboolaRequests(request *openrtb2.BidRequest) (taboolaRequests []*openrtb2.BidRequest, errors []error) {
modifiedRequest := *request
var nativeImp []openrtb2.Imp
var bannerImp []openrtb2.Imp
var errs []error

var taboolaExt openrtb_ext.ImpExtTaboola
Expand All @@ -114,6 +199,12 @@ func createTaboolaRequest(request *openrtb2.BidRequest) (taboolaRequest *openrtb
imp.BidFloor = taboolaExt.BidFloor
modifiedRequest.Imp[i] = imp
}

if modifiedRequest.Imp[i].Banner != nil {
bannerImp = append(bannerImp, modifiedRequest.Imp[i])
} else if modifiedRequest.Imp[i].Native != nil {
nativeImp = append(nativeImp, modifiedRequest.Imp[i])
}
}

publisher := &openrtb2.Publisher{
Expand Down Expand Up @@ -145,20 +236,25 @@ func createTaboolaRequest(request *openrtb2.BidRequest) (taboolaRequest *openrtb
modifiedRequest.BAdv = taboolaExt.BAdv
}

return &modifiedRequest, errs
taboolaRequests = append(taboolaRequests, overrideBidRequestImp(&modifiedRequest, nativeImp))
taboolaRequests = append(taboolaRequests, overrideBidRequestImp(&modifiedRequest, bannerImp))

return taboolaRequests, errs
}

func getMediaType(impID string, imps []openrtb2.Imp) (openrtb_ext.BidType, error) {
for _, imp := range imps {
if imp.ID == impID {
if imp.Banner != nil {
return openrtb_ext.BidTypeBanner, nil
} else if imp.Native != nil {
return openrtb_ext.BidTypeNative, nil
}
}
}

return "", &errortypes.BadInput{
Message: fmt.Sprintf("Failed to find banner impression \"%s\" ", impID),
Message: fmt.Sprintf("Failed to find banner/native impression \"%s\" ", impID),
}
}

Expand All @@ -171,3 +267,25 @@ func evaluateDomain(publisherDomain string, request *openrtb2.BidRequest) (resul
}
return ""
}

func overrideBidRequestImp(originBidRequest *openrtb2.BidRequest, imp []openrtb2.Imp) (bidRequest *openrtb2.BidRequest) {
bidRequestResult := *originBidRequest
bidRequestResult.Imp = imp
return &bidRequestResult
}

func overrideEventTrackers(nativePayload *nativeResponse.Response) {
// convert eventrackers to the deprecated imptrackers and jstracker because it's not supported in native 1.1v
for _, eventTracker := range nativePayload.EventTrackers {
if eventTracker.Event != native1.EventTypeImpression {
continue
}
switch eventTracker.Method {
case native1.EventTrackingMethodImage:
nativePayload.ImpTrackers = append(nativePayload.ImpTrackers, eventTracker.URL)
case native1.EventTrackingMethodJS:
nativePayload.JSTracker = fmt.Sprintf("<script src=\"%s\"></script>", eventTracker.URL)
}
}
nativePayload.EventTrackers = nil
}
18 changes: 16 additions & 2 deletions adapters/taboola/taboola_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package taboola
import (
"github.com/prebid/prebid-server/adapters/adapterstest"
"github.com/prebid/prebid-server/config"
"github.com/stretchr/testify/assert"
"testing"
)

Expand All @@ -11,12 +12,25 @@ import (
)

func TestJsonSamples(t *testing.T) {
bidder, buildErr := Builder(openrtb_ext.BidderOutbrain, config.Adapter{
Endpoint: "http://whatever.com"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"})
bidder, buildErr := Builder(openrtb_ext.BidderTaboola, config.Adapter{
Endpoint: "http://{{.MediaType}}.whatever.com/{{.Host}}/{{.PublisherID}}"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"})

if buildErr != nil {
t.Fatalf("Builder returned unexpected error %v", buildErr)
}

adapterstest.RunJSONBidderTest(t, "taboolatest", bidder)
}

func TestEmptyExternalUrl(t *testing.T) {
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.hostName)
}
2 changes: 1 addition & 1 deletion adapters/taboola/taboolatest/exemplary/banner.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
"httpCalls": [
{
"expectedRequest": {
"uri": "http://whatever.com/publisher-id",
"uri": "http://display.whatever.com/hosturl.com/publisher-id",
"body": {
"id": "request-id",
"imp": [
Expand Down
Loading

0 comments on commit 4109b90

Please sign in to comment.