Skip to content
This repository has been archived by the owner on Dec 22, 2022. It is now read-only.

Commit

Permalink
Add Adtarget server adapter (prebid#1319)
Browse files Browse the repository at this point in the history
* Add Adtarget server adapter

* Suggested changes for Adtarget
  • Loading branch information
GeneGenie authored Jun 9, 2020
1 parent e5c0cb3 commit a0ad55b
Show file tree
Hide file tree
Showing 24 changed files with 791 additions and 0 deletions.
189 changes: 189 additions & 0 deletions adapters/adtarget/adtarget.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
package adtarget

import (
"encoding/json"
"fmt"
"net/http"

"github.com/mxmCherry/openrtb"
"github.com/prebid/prebid-server/adapters"
"github.com/prebid/prebid-server/errortypes"
"github.com/prebid/prebid-server/openrtb_ext"
)

type AdtargetAdapter struct {
endpoint string
}

type adtargetImpExt struct {
Adtarget openrtb_ext.ExtImpAdtarget `json:"adtarget"`
}

func (a *AdtargetAdapter) MakeRequests(request *openrtb.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {

totalImps := len(request.Imp)
errors := make([]error, 0, totalImps)
imp2source := make(map[int][]int)

for i := 0; i < totalImps; i++ {

sourceId, err := validateImpressionAndSetExt(&request.Imp[i])

if err != nil {
errors = append(errors, err)
continue
}

if _, ok := imp2source[sourceId]; !ok {
imp2source[sourceId] = make([]int, 0, totalImps-i)
}

imp2source[sourceId] = append(imp2source[sourceId], i)

}

totalReqs := len(imp2source)
if 0 == totalReqs {
return nil, errors
}

headers := http.Header{}
headers.Add("Content-Type", "application/json;charset=utf-8")
headers.Add("Accept", "application/json")

reqs := make([]*adapters.RequestData, 0, totalReqs)

imps := request.Imp
request.Imp = make([]openrtb.Imp, 0, len(imps))
for sourceId, impIndexes := range imp2source {
request.Imp = request.Imp[:0]

for i := 0; i < len(impIndexes); i++ {
request.Imp = append(request.Imp, imps[impIndexes[i]])
}

body, err := json.Marshal(request)
if err != nil {
errors = append(errors, fmt.Errorf("error while encoding bidRequest, err: %s", err))
return nil, errors
}

reqs = append(reqs, &adapters.RequestData{
Method: "POST",
Uri: a.endpoint + fmt.Sprintf("?aid=%d", sourceId),
Body: body,
Headers: headers,
})
}

return reqs, errors
}

func (a *AdtargetAdapter) MakeBids(bidReq *openrtb.BidRequest, unused *adapters.RequestData, httpRes *adapters.ResponseData) (*adapters.BidderResponse, []error) {

if httpRes.StatusCode == http.StatusNoContent {
return nil, nil
}
if httpRes.StatusCode == http.StatusBadRequest {
return nil, []error{&errortypes.BadInput{
Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info", httpRes.StatusCode),
}}
}
var bidResp openrtb.BidResponse
if err := json.Unmarshal(httpRes.Body, &bidResp); err != nil {
return nil, []error{&errortypes.BadServerResponse{
Message: fmt.Sprintf("error while decoding response, err: %s", err),
}}
}

bidResponse := adapters.NewBidderResponse()
var errors []error

var impOK bool
for _, sb := range bidResp.SeatBid {
for i := 0; i < len(sb.Bid); i++ {

bid := sb.Bid[i]

impOK = false
mediaType := openrtb_ext.BidTypeBanner
for _, imp := range bidReq.Imp {
if imp.ID == bid.ImpID {

impOK = true

if imp.Video != nil {
mediaType = openrtb_ext.BidTypeVideo
break
}
}
}

if !impOK {
errors = append(errors, &errortypes.BadServerResponse{
Message: fmt.Sprintf("ignoring bid id=%s, request doesn't contain any impression with id=%s", bid.ID, bid.ImpID),
})
continue
}

bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
Bid: &bid,
BidType: mediaType,
})
}
}

return bidResponse, errors
}

func validateImpressionAndSetExt(imp *openrtb.Imp) (int, error) {

if imp.Banner == nil && imp.Video == nil {
return 0, &errortypes.BadInput{
Message: fmt.Sprintf("ignoring imp id=%s, Adtarget supports only Video and Banner", imp.ID),
}
}

if 0 == len(imp.Ext) {
return 0, &errortypes.BadInput{
Message: fmt.Sprintf("ignoring imp id=%s, extImpBidder is empty", imp.ID),
}
}

var bidderExt adapters.ExtImpBidder

if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil {
return 0, &errortypes.BadInput{
Message: fmt.Sprintf("ignoring imp id=%s, error while decoding extImpBidder, err: %s", imp.ID, err),
}
}

impExt := openrtb_ext.ExtImpAdtarget{}
err := json.Unmarshal(bidderExt.Bidder, &impExt)
if err != nil {
return 0, &errortypes.BadInput{
Message: fmt.Sprintf("ignoring imp id=%s, error while decoding impExt, err: %s", imp.ID, err),
}
}

// common extension for all impressions
var impExtBuffer []byte

impExtBuffer, err = json.Marshal(&adtargetImpExt{
Adtarget: impExt,
})

if impExt.BidFloor > 0 {
imp.BidFloor = impExt.BidFloor
}

imp.Ext = impExtBuffer

return impExt.SourceId, nil
}

func NewAdtargetBidder(endpoint string) *AdtargetAdapter {
return &AdtargetAdapter{
endpoint: endpoint,
}
}
11 changes: 11 additions & 0 deletions adapters/adtarget/adtarget_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package adtarget

import (
"testing"

"github.com/prebid/prebid-server/adapters/adapterstest"
)

func TestJsonSamples(t *testing.T) {
adapterstest.RunJSONBidderTest(t, "adtargettest", NewAdtargetBidder("http://ghb.console.adtarget.com.tr/pbs/ortb"))
}
88 changes: 88 additions & 0 deletions adapters/adtarget/adtargettest/exemplary/media-type-mapping.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
{
"mockBidRequest": {
"id": "test-request-id",
"imp": [
{
"id": "test-imp-id",
"video": {
"w": 900,
"h": 250,
"mimes": [
"video/x-flv",
"video/mp4"
]
},
"ext": {
"bidder": {
"aid": 1000
}
}
}
]
},

"httpCalls": [
{
"expectedRequest": {
"uri": "http://ghb.console.adtarget.com.tr/pbs/ortb?aid=1000",
"body": {
"id": "test-request-id",
"imp": [
{
"id":"test-imp-id",
"video": {
"w": 900,
"h": 250,
"mimes": [
"video/x-flv",
"video/mp4"
]
},
"ext": {
"adtarget": {
"aid": 1000
}
}
}
]
}
},
"mockResponse": {
"status": 200,
"body": {
"id": "test-request-id",
"seatbid": [
{
"bid": [
{
"id": "test-bid-id",
"impid": "test-imp-id",
"price": 3.5,
"w": 900,
"h": 250
}
]
}
]
}
}
}
],
"expectedBidResponses": [
{
"currency": "USD",
"bids": [
{
"bid": {
"id": "test-bid-id",
"impid": "test-imp-id",
"price": 3.5,
"w": 900,
"h": 250
},
"type": "video"
}
]
}
]
}
62 changes: 62 additions & 0 deletions adapters/adtarget/adtargettest/exemplary/simple-banner.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
{
"mockBidRequest": {
"id": "test-request-id",
"imp": [
{
"id": "test-imp-id",
"banner": {
"format": [
{
"w": 300,
"h": 250
},
{
"w": 300,
"h": 600
}
]
},
"ext": {
"bidder": {
"aid": 1000,
"siteId": 1234,
"bidFloor": 20
}
}
}
]
},

"httpCalls": [
{
"expectedRequest": {
"uri": "http://ghb.console.adtarget.com.tr/pbs/ortb?aid=1000",
"body": {
"id": "test-request-id",
"imp": [
{
"id":"test-imp-id",
"banner": {
"format": [
{"w":300,"h":250},
{"w":300,"h":600}
]
},
"bidfloor": 20,
"ext": {
"adtarget": {
"aid": 1000,
"siteId": 1234,
"bidFloor": 20
}
}
}
]
}
},
"mockResponse": {
"status": 204
}
}
]
}
Loading

0 comments on commit a0ad55b

Please sign in to comment.