forked from prebid/prebid-server
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Datablocks Adapter (prebid#1095)
* datablocks bid adapter * ttx * add test json * add coverage * redo ttx * formatted * better error handling * additional tests and recomended fixes
- Loading branch information
1 parent
6a7d562
commit 07ae3c4
Showing
27 changed files
with
1,229 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,188 @@ | ||
package datablocks | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"github.com/golang/glog" | ||
"github.com/mxmCherry/openrtb" | ||
"github.com/prebid/prebid-server/adapters" | ||
"github.com/prebid/prebid-server/errortypes" | ||
"github.com/prebid/prebid-server/macros" | ||
"github.com/prebid/prebid-server/openrtb_ext" | ||
"net/http" | ||
"strconv" | ||
"text/template" | ||
) | ||
|
||
type DatablocksAdapter struct { | ||
EndpointTemplate template.Template | ||
} | ||
|
||
func (a *DatablocksAdapter) MakeRequests(request *openrtb.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { | ||
|
||
errs := make([]error, 0, len(request.Imp)) | ||
headers := http.Header{ | ||
"Content-Type": {"application/json"}, | ||
"Accept": {"application/json"}, | ||
} | ||
|
||
// Pull the host and source ID info from the bidder params. | ||
reqImps, err := splitImpressions(request.Imp) | ||
|
||
if err != nil { | ||
errs = append(errs, err) | ||
} | ||
|
||
requests := []*adapters.RequestData{} | ||
|
||
for reqExt, reqImp := range reqImps { | ||
request.Imp = reqImp | ||
reqJson, err := json.Marshal(request) | ||
|
||
if err != nil { | ||
errs = append(errs, err) | ||
continue | ||
} | ||
|
||
urlParams := macros.EndpointTemplateParams{Host: reqExt.Host, SourceId: strconv.Itoa(reqExt.SourceId)} | ||
url, err := macros.ResolveMacros(a.EndpointTemplate, urlParams) | ||
|
||
if err != nil { | ||
errs = append(errs, err) | ||
continue | ||
} | ||
|
||
request := adapters.RequestData{ | ||
Method: "POST", | ||
Uri: url, | ||
Body: reqJson, | ||
Headers: headers} | ||
|
||
requests = append(requests, &request) | ||
} | ||
|
||
return requests, errs | ||
} | ||
|
||
/* | ||
internal original request in OpenRTB, external = result of us having converted it (what comes out of MakeRequests) | ||
*/ | ||
func (a *DatablocksAdapter) MakeBids( | ||
internalRequest *openrtb.BidRequest, | ||
externalRequest *adapters.RequestData, | ||
response *adapters.ResponseData, | ||
) (*adapters.BidderResponse, []error) { | ||
|
||
if response.StatusCode == http.StatusNoContent { | ||
return nil, nil | ||
} | ||
|
||
if response.StatusCode != http.StatusOK { | ||
return nil, []error{&errortypes.BadServerResponse{ | ||
Message: fmt.Sprintf("ERR, response with status %d", response.StatusCode), | ||
}} | ||
} | ||
|
||
var bidResp openrtb.BidResponse | ||
|
||
if err := json.Unmarshal(response.Body, &bidResp); err != nil { | ||
return nil, []error{err} | ||
} | ||
|
||
bidResponse := adapters.NewBidderResponse() | ||
bidResponse.Currency = bidResp.Cur | ||
|
||
for _, seatBid := range bidResp.SeatBid { | ||
for i := 0; i < len(seatBid.Bid); i++ { | ||
bid := seatBid.Bid[i] | ||
bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ | ||
Bid: &bid, | ||
BidType: getMediaType(bid.ImpID, internalRequest.Imp), | ||
}) | ||
} | ||
} | ||
|
||
return bidResponse, nil | ||
} | ||
|
||
func splitImpressions(imps []openrtb.Imp) (map[openrtb_ext.ExtImpDatablocks][]openrtb.Imp, error) { | ||
|
||
var m = make(map[openrtb_ext.ExtImpDatablocks][]openrtb.Imp) | ||
|
||
for _, imp := range imps { | ||
bidderParams, err := getBidderParams(&imp) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
v, ok := m[*bidderParams] | ||
if ok { | ||
m[*bidderParams] = append(v, imp) | ||
} else { | ||
m[*bidderParams] = []openrtb.Imp{imp} | ||
} | ||
} | ||
|
||
return m, nil | ||
} | ||
|
||
func getBidderParams(imp *openrtb.Imp) (*openrtb_ext.ExtImpDatablocks, error) { | ||
var bidderExt adapters.ExtImpBidder | ||
if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil { | ||
return nil, &errortypes.BadInput{ | ||
Message: fmt.Sprintf("Missing bidder ext: %s", err.Error()), | ||
} | ||
} | ||
var datablocksExt openrtb_ext.ExtImpDatablocks | ||
if err := json.Unmarshal(bidderExt.Bidder, &datablocksExt); err != nil { | ||
return nil, &errortypes.BadInput{ | ||
Message: fmt.Sprintf("Cannot Resolve host or sourceId: %s", err.Error()), | ||
} | ||
} | ||
|
||
if datablocksExt.SourceId < 1 { | ||
return nil, &errortypes.BadInput{ | ||
Message: "Invalid/Missing SourceId", | ||
} | ||
} | ||
|
||
if len(datablocksExt.Host) < 1 { | ||
return nil, &errortypes.BadInput{ | ||
Message: "Invalid/Missing Host", | ||
} | ||
} | ||
|
||
return &datablocksExt, nil | ||
} | ||
|
||
func getMediaType(impID string, imps []openrtb.Imp) openrtb_ext.BidType { | ||
|
||
bidType := openrtb_ext.BidTypeBanner | ||
|
||
for _, imp := range imps { | ||
if imp.ID == impID { | ||
if imp.Video != nil { | ||
bidType = openrtb_ext.BidTypeVideo | ||
break | ||
} else if imp.Native != nil { | ||
bidType = openrtb_ext.BidTypeNative | ||
break | ||
} else { | ||
bidType = openrtb_ext.BidTypeBanner | ||
break | ||
} | ||
} | ||
} | ||
|
||
return bidType | ||
} | ||
|
||
func NewDatablocksBidder(endpoint string) *DatablocksAdapter { | ||
template, err := template.New("endpointTemplate").Parse(endpoint) | ||
if err != nil { | ||
glog.Fatal("Unable to parse endpoint url template") | ||
return nil | ||
} | ||
|
||
return &DatablocksAdapter{EndpointTemplate: *template} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package datablocks | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/prebid/prebid-server/adapters/adapterstest" | ||
) | ||
|
||
func TestJsonSamples(t *testing.T) { | ||
adapterstest.RunJSONBidderTest(t, "datablockstest", NewDatablocksBidder("http://{{.Host}}/openrtb2?sid={{.SourceId}}")) | ||
} |
160 changes: 160 additions & 0 deletions
160
adapters/datablocks/datablockstest/exemplary/multi-request.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
{ | ||
"mockBidRequest": | ||
{ | ||
"id": "some-request-id", | ||
"imp": [ | ||
{ | ||
"id": "some-impression-id", | ||
"banner": | ||
{ | ||
"format": [ | ||
{ | ||
"w": 300, | ||
"h": 250 | ||
}] | ||
}, | ||
"ext": | ||
{ | ||
"bidder": | ||
{ | ||
"host": "search.nutella.datablocks.net", | ||
"sourceId": 906295 | ||
} | ||
} | ||
},{ | ||
"id": "some-impression-id2", | ||
"banner": | ||
{ | ||
"format": [{ | ||
"w": 300, | ||
"h": 600 | ||
}] | ||
}, | ||
"ext": | ||
{ | ||
"bidder": | ||
{ | ||
"host": "search.nutella.datablocks.net", | ||
"sourceId": 906295 | ||
} | ||
} | ||
}], | ||
"site": | ||
{ | ||
"page": "prebid.org" | ||
}, | ||
"device": | ||
{ | ||
"ip": "8.8.8.10" | ||
}, | ||
"at": 1, | ||
"tmax": 500 | ||
}, | ||
"httpCalls": [ | ||
{ | ||
"expectedRequest": | ||
{ | ||
"uri": "http://search.nutella.datablocks.net/openrtb2?sid=906295", | ||
"body": | ||
{ | ||
"id": "some-request-id", | ||
"imp": [ | ||
{ | ||
"id": "some-impression-id", | ||
"banner": | ||
{ | ||
"format": [ | ||
{ | ||
"w": 300, | ||
"h": 250 | ||
}] | ||
}, | ||
"ext": | ||
{ | ||
"bidder": | ||
{ | ||
"host": "search.nutella.datablocks.net", | ||
"sourceId": 906295 | ||
} | ||
} | ||
},{ | ||
"id": "some-impression-id2", | ||
"banner": | ||
{ | ||
"format": [ | ||
{ | ||
"w": 300, | ||
"h": 600 | ||
}] | ||
}, | ||
"ext": | ||
{ | ||
"bidder": | ||
{ | ||
"host": "search.nutella.datablocks.net", | ||
"sourceId": 906295 | ||
} | ||
} | ||
}], | ||
"site": | ||
{ | ||
"page": "prebid.org" | ||
}, | ||
"device": | ||
{ | ||
"ip": "8.8.8.10" | ||
}, | ||
"at": 1, | ||
"tmax": 500 | ||
} | ||
}, | ||
"mockResponse": | ||
{ | ||
"status": 200, | ||
"body": | ||
{ | ||
"id": "some-request-id", | ||
"bidid": "183975330-5-29038-2", | ||
"seatbid": [ | ||
{ | ||
"seat": "906295", | ||
"bid": [ | ||
{ | ||
"id": "2181314349", | ||
"impid": "some-impression-id", | ||
"adm": "<style>.text_preview{padding:14px;overflow:hidden;display:flex;flex-direction:column;justify-content:center;font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:14px;line-height:20px;margin:0;padding:0;color:#333;background:#fff}.text_decription{min-width:150px;padding:5px;flex-grow:0;}.title_preview a{color:#00f;font-weight:700;text-decoration:none}.description_preview{padding:0 0 20px;overflow:hidden;text-overflow:ellipsis}.click_url_preview{color:green}.image_container{position:relative;width:160;height:120}.image_container img{max-height:100%;max-width:100%}.loading{background:url() center no-repeat #eee;height:100%;width:100%;top:0;left:0;position:absolute;border-radius:0}</style><style>.text_boundary {width:300px;height:250px;}</style><div class=\"text_preview text_boundary\"><div class=\"text_decription\"><div class=\"title_preview\"><a href=\"https://track.nutella.datablocks.net/c/267237/?fcid=2181314349\" target=\"_top\">Datablocks Inc.</a></div><div class=\"description_preview\">Datablocks provides world class \"Software as a Service\" (SaaS) solutions to its clients.</div><a class=\"click_url_preview\" target=\"_top\" href=\"https://track.nutella.datablocks.net/c/267237/?fcid=2181314349\">www.datablocks.net</a></div></div><img alt=\"\" src=\"https://impression.nutella.datablocks.net/i/267237/?fcid=2181314349&pixel=1\" width=\"1\" height=\"1\" ></div>", | ||
"price": 13.37, | ||
"cid": "906293", | ||
"adid": "906297", | ||
"crid": "906299", | ||
"w": 300, | ||
"h": 250 | ||
}] | ||
}], | ||
"cur": "USD", | ||
"ext": | ||
{} | ||
} | ||
} | ||
}], | ||
"expectedBidResponses": [ | ||
{ | ||
"currency": "USD", | ||
"bids": [ | ||
{ | ||
"bid": | ||
{ | ||
"id": "2181314349", | ||
"impid": "some-impression-id", | ||
"adm": "<style>.text_preview{padding:14px;overflow:hidden;display:flex;flex-direction:column;justify-content:center;font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:14px;line-height:20px;margin:0;padding:0;color:#333;background:#fff}.text_decription{min-width:150px;padding:5px;flex-grow:0;}.title_preview a{color:#00f;font-weight:700;text-decoration:none}.description_preview{padding:0 0 20px;overflow:hidden;text-overflow:ellipsis}.click_url_preview{color:green}.image_container{position:relative;width:160;height:120}.image_container img{max-height:100%;max-width:100%}.loading{background:url() center no-repeat #eee;height:100%;width:100%;top:0;left:0;position:absolute;border-radius:0}</style><style>.text_boundary {width:300px;height:250px;}</style><div class=\"text_preview text_boundary\"><div class=\"text_decription\"><div class=\"title_preview\"><a href=\"https://track.nutella.datablocks.net/c/267237/?fcid=2181314349\" target=\"_top\">Datablocks Inc.</a></div><div class=\"description_preview\">Datablocks provides world class \"Software as a Service\" (SaaS) solutions to its clients.</div><a class=\"click_url_preview\" target=\"_top\" href=\"https://track.nutella.datablocks.net/c/267237/?fcid=2181314349\">www.datablocks.net</a></div></div><img alt=\"\" src=\"https://impression.nutella.datablocks.net/i/267237/?fcid=2181314349&pixel=1\" width=\"1\" height=\"1\" ></div>", | ||
"price": 13.37, | ||
"cid": "906293", | ||
"adid": "906297", | ||
"crid": "906299", | ||
"w": 300, | ||
"h": 250 | ||
}, | ||
"type": "banner" | ||
}] | ||
}] | ||
} |
Oops, something went wrong.