Skip to content

Commit

Permalink
New Adapter: ResetDigital
Browse files Browse the repository at this point in the history
  • Loading branch information
bruno-siira committed Feb 5, 2024
1 parent 3e5918d commit 70de190
Show file tree
Hide file tree
Showing 5 changed files with 443 additions and 0 deletions.
260 changes: 260 additions & 0 deletions adapters/resetdigital/resetdigital.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,260 @@
package resetdigital

import (
"encoding/json"
"fmt"
"net/http"
"strconv"
"text/template"

"github.com/prebid/openrtb/v20/openrtb2"
"github.com/prebid/prebid-server/v2/adapters"
"github.com/prebid/prebid-server/v2/config"
"github.com/prebid/prebid-server/v2/openrtb_ext"
)

// MaximumBids is the maximum number of bids that can be returned by this adapter.
const (
MaxBids = 1
)

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

type resetDigitalRequest struct {
Site resetDigitalRequestSite `json:"site"`
Imps []resetDigitalRequesImps `json:"imps"`
}

type resetDigitalRequestSite struct {
Domain string `json:"domain"`
Referrer string `json:"referrer"`
}

type resetDigitalRequesImps struct {
ZoneID struct {
PlacementID string `json:"placementId"`
} `json:"zone_id"`
BidID string `json:"bid_id"`
ImpID string `json:"imp_id"`
Ext struct {
Gpid string `json:"gpid"`
} `json:"ext"`
Sizes [][]int64 `json:"sizes"`
MediaTypes struct {
Banner struct {
Sizes [][]int64 `json:"sizes"`
} `json:"banner"`
Video struct {
Sizes [][]int64 `json:"sizes"`
} `json:"video"`
} `json:"media_types"`
}

func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) {
template, err := template.New("endpointTemplate").Parse(config.Endpoint)
if err != nil {
return nil, fmt.Errorf("unable to parse endpoint url template: %v", err)
}

bidder := &adapter{
endpoint: template,
}

return bidder, nil
}
func getHeaders(request *openrtb2.BidRequest) http.Header {
headers := http.Header{}

if request.Device != nil && request.Site != nil {
addNonEmptyHeaders(&headers, map[string]string{
"Referer": request.Site.Page,
"Accept-Language": request.Device.Language,
"User-Agent": request.Device.UA,
"X-Forwarded-For": request.Device.IP,
"X-Real-Ip": request.Device.IP,
"Content-Type": "application/json;charset=utf-8",
"Accept": "application/json",
})
}

return headers
}
func addNonEmptyHeaders(headers *http.Header, headerValues map[string]string) {
for key, value := range headerValues {
if len(value) > 0 {
headers.Add(key, value)
}
}
}

func getReferer(request *openrtb2.BidRequest) string {
if request.Site == nil {
return ""
}

return request.Site.Domain
}

func getCurrency(request *openrtb2.BidRequest) string {
if len(request.Cur) == 0 {
return "USD"
}

return request.Cur[0]
}

func (a *adapter) MakeRequests(requestData *openrtb2.BidRequest, requestInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
var (
requests []*adapters.RequestData
errors []error
)

referer := getReferer(requestData)
currency := getCurrency(requestData)

if referer == currency {
return nil, nil
}

for i := range requestData.Imp {
imp := requestData.Imp[i]
bidType, err := getBidType(imp)

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

splittedRequestData := processDataFromRequest(requestData, imp, bidType)

requestBody, err := json.Marshal(splittedRequestData)
if err != nil {
errors = append(errors, err)
continue
}

requests = append(requests, &adapters.RequestData{
Method: "POST",
Uri: a.endpointUri,
Body: requestBody,
Headers: getHeaders(requestData),
})
}

return requests, errors
}

func processDataFromRequest(requestData *openrtb2.BidRequest, imp openrtb2.Imp, bidType openrtb_ext.BidType) resetDigitalRequest {

var resetDigitalRequestData resetDigitalRequest
resetDigitalRequestData.Site.Domain = requestData.Site.Domain
resetDigitalRequestData.Site.Referrer = requestData.Site.Page

resetDigitalRequestData.Imps = append(resetDigitalRequestData.Imps, resetDigitalRequesImps{})
resetDigitalRequestData.Imps[0].BidID = requestData.ID
resetDigitalRequestData.Imps[0].ImpID = imp.ID

if bidType == openrtb_ext.BidTypeBanner {
resetDigitalRequestData.Imps[0].MediaTypes.Banner.Sizes = append(resetDigitalRequestData.Imps[0].MediaTypes.Banner.Sizes, []int64{imp.Banner.Format[0].W, imp.Banner.Format[0].H})
}
if bidType == openrtb_ext.BidTypeVideo {
resetDigitalRequestData.Imps[0].MediaTypes.Video.Sizes = append(resetDigitalRequestData.Imps[0].MediaTypes.Banner.Sizes, []int64{*imp.Video.W, *imp.Video.H})
}

return resetDigitalRequestData

}

func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) {
if response.StatusCode == http.StatusNoContent {
return nil, nil
}
if response.StatusCode == http.StatusBadRequest {
return nil, []error{fmt.Errorf("bad request")}
}
if response.StatusCode != http.StatusOK {
return nil, []error{fmt.Errorf("unexpected status code: %d", response.StatusCode)}
}

if err := json.Unmarshal(response.Body, &response); err != nil {
return nil, []error{err}
}
bidResponse := adapters.NewBidderResponseWithBidsCapacity(MaxBids)
//check no bids
jsonData := make(map[string]interface{})

json.Unmarshal([]byte(response.Body), &jsonData)
//Always one bid
bid := getBidFromResponse(jsonData)

bidType, err := getBidType(internalRequest.Imp[0])
if err != nil {
// handle error
return nil, []error{err}
}
bidResponse.Currency = getCurrency(internalRequest)
bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
Bid: bid,
BidType: bidType,
})

return bidResponse, nil
}

func getBidFromResponse(requestData map[string]interface{}) *openrtb2.Bid {
processData := requestData["bids"].([]interface{})[0].(map[string]interface{})
fmt.Printf("jsonData: %v\n", processData)

bid := &openrtb2.Bid{
ID: processData["bid_id"].(string),
Price: getBidPrice(processData),
ImpID: processData["imp_id"].(string),
CrID: processData["crid"].(string),
}
//if HTML is filled on jsonData then fill ADM with it
if value, ok := processData["html"].(string); ok {
bid.AdM = value
}
//if Width and Height are filled on jsonData then fill W and H with it
if value, ok := processData["w"].(string); ok {

i, _ := strconv.ParseInt(value, 10, 64)
if i > 0 {
bid.W = i
}
}
if value, ok := processData["h"].(string); ok {
i, _ := strconv.ParseInt(value, 10, 64)
if i > 0 {
bid.H = i
}
}
//if Bid Price is 0 then return nil
if bid.Price == 0 {
return nil
}

return bid
}

func getBidPrice(requestData map[string]interface{}) float64 {
if value, ok := requestData["cpm"].(float64); ok {
return value
}
return 0.0 // Default value if "cpm" doesn't exist or is not a float64
}

func getBidType(imp openrtb2.Imp) (openrtb_ext.BidType, error) {
if imp.Banner != nil {
return openrtb_ext.BidTypeBanner, nil
} else if imp.Video != nil {
return openrtb_ext.BidTypeVideo, nil
} else if imp.Audio != nil {
return openrtb_ext.BidTypeAudio, nil
}

return "", fmt.Errorf("failed to find matching imp for bid %s", imp.ID)
}
87 changes: 87 additions & 0 deletions adapters/resetdigital/resetdigital_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package resetdigital

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

"github.com/prebid/openrtb/v20/openrtb2"
"github.com/prebid/prebid-server/v2/adapters"
"github.com/stretchr/testify/assert"
)

func TestMakeRequests(t *testing.T) {
bidder := new(adapter)

request := &openrtb2.BidRequest{
ID: "12345",

Imp: []openrtb2.Imp{{
ID: "001",

Banner: &openrtb2.Banner{
Format: []openrtb2.Format{
{W: 300, H: 250},
},
},
Ext: json.RawMessage(``),
}},
Site: &openrtb2.Site{
Domain: "https://test.com",
Page: "https://test.com/2016/06/12",
},
Cur: []string{"USD"},
Device: &openrtb2.Device{
UA: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36",
IP: "127.0.0.1",
Language: "EN",
},
}

reqs, errs := bidder.MakeRequests(request, &adapters.ExtraRequestInfo{})

assert.Empty(t, errs, "Got unexpected errors while building HTTP requests: %v", errs)
assert.Equal(t, 1, len(reqs), "Unexpected number of HTTP requests. Got %d. Expected %d", len(reqs), 1)
}

func TestMakeBids(t *testing.T) {
request := &openrtb2.BidRequest{
ID: "test-request-id",
Imp: []openrtb2.Imp{{
ID: "test-imp-id",
Banner: &openrtb2.Banner{
Format: []openrtb2.Format{{
W: 320,
H: 250,
}},
},
Ext: json.RawMessage(`{"bidder": {
"accountId": 2763,
"siteId": 68780,
"zoneId": 327642
}}`),
}},
Ext: json.RawMessage(``),
}

requestJson, _ := json.Marshal(request)
reqData := &adapters.RequestData{
Method: "POST",
Uri: "test-uri",
Body: requestJson,
Headers: nil,
}

httpResp := &adapters.ResponseData{
StatusCode: http.StatusOK,
Body: []byte(`{"bids":[{"bid_id":"01","imp_id":"001","cpm":10.00,"cid":"1002088","crid":"1000763-1002088","adid":"1002088","w":"300","h":"250","seat":"resetdigital","html":"<scriptsrc=\"https://data.resetdigital.co/evts?S0B=1&R0E=1&R0M=3_3&testad=US-HEADER-15&R0A=1000048_1001096_1001117_1627360746&R0P=resetio_1234_muscleandfitness.com_Site_1_Banner&R0L=*_*_*_*_*&R0D=*_*_*_*_*_*&R0B=*_*_*\"type=\"text/javascript\"></script><imagesrc='https://adsreq.resetdigital.co?brid=0000000000000001'/><imagesrc='https://sync2.resetdigital.co/hbsync?ck=0000000000000001'/>"}]}`),
}

bidder := new(adapter)
bidResponse, errs := bidder.MakeBids(request, reqData, httpResp)

assert.Empty(t, errs, "Expected 0 errors. Got %d", len(errs))

assert.Equal(t, float64(10), bidResponse.Bids[0].Bid.Price,
"Expected Price 10. Got: %s", bidResponse.Bids[0].Bid.Price)
}
Loading

0 comments on commit 70de190

Please sign in to comment.