diff --git a/adapters/adot/adot.go b/adapters/adot/adot.go new file mode 100644 index 00000000000..9b75d6692df --- /dev/null +++ b/adapters/adot/adot.go @@ -0,0 +1,190 @@ +package adot + +import ( + "encoding/json" + "fmt" + "github.com/buger/jsonparser" + "github.com/prebid/prebid-server/config" + "net/http" + "net/url" + "strconv" + + "github.com/mxmCherry/openrtb" + "github.com/prebid/prebid-server/adapters" + "github.com/prebid/prebid-server/errortypes" + "github.com/prebid/prebid-server/openrtb_ext" +) + +type AdotAdapter struct { + endpoint string +} + +// NewGridBidder configure bidder endpoint +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (adapters.Bidder, error) { + _, err := url.ParseRequestURI(config.Endpoint) + if len(config.Endpoint) > 0 && err != nil { + return nil, fmt.Errorf("unable to parse endpoint url: %v", err) + } + + bidder := &AdotAdapter{ + endpoint: config.Endpoint, + } + return bidder, nil +} + +// MakeRequests makes the HTTP requests which should be made to fetch bids. +func (a *AdotAdapter) MakeRequests(request *openrtb.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { + var errors = make([]error, 0) + + reqJSON, err := json.Marshal(request) + if err != nil { + errors = append(errors, err) + return nil, errors + } + reqJSON = addParallaxIfNecessary(reqJSON) + + headers := http.Header{} + headers.Add("Content-Type", "application/json;charset=utf-8") + + return []*adapters.RequestData{{ + Method: "POST", + Uri: a.endpoint, + Body: reqJSON, + Headers: headers, + }}, errors +} + +// MakeBids unpacks the server's response into Bids. +func (a *AdotAdapter) 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.StatusBadRequest { + return nil, []error{&errortypes.BadInput{ + Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info", response.StatusCode), + }} + } + + if response.StatusCode != http.StatusOK { + return nil, []error{&errortypes.BadServerResponse{ + Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info", response.StatusCode), + }} + } + + var bidResp openrtb.BidResponse + if err := json.Unmarshal(response.Body, &bidResp); err != nil { + return nil, []error{err} + } + + bidResponse := adapters.NewBidderResponseWithBidsCapacity(1) + + for _, sb := range bidResp.SeatBid { + for i := range sb.Bid { + if bidType, err := getMediaTypeForBid(&sb.Bid[i], internalRequest); err == nil { + bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ + Bid: &sb.Bid[i], + BidType: bidType, + }) + } + } + } + return bidResponse, nil + +} + +// getMediaTypeForBid determines which type of bid. +func getMediaTypeForBid(bid *openrtb.Bid, internalRequest *openrtb.BidRequest) (openrtb_ext.BidType, error) { + if bid == nil || internalRequest == nil { + return "", fmt.Errorf("the bid request object is nil") + } + + impID := bid.ImpID + + for _, imp := range internalRequest.Imp { + if imp.ID == impID { + 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 + } else if imp.Native != nil { + return openrtb_ext.BidTypeNative, nil + } + } + } + + return "", fmt.Errorf("unrecognized bid type in response from adot") +} + +func addParallaxIfNecessary(reqJSON []byte) []byte { + var adotJSON []byte + var err error + + adotRequest, parallaxError := addParallaxInRequest(reqJSON) + if parallaxError == nil { + adotJSON, err = json.Marshal(adotRequest) + if err != nil { + adotJSON = reqJSON + } + } else { + adotJSON = reqJSON + } + + return adotJSON +} + +func addParallaxInRequest(data []byte) (map[string]interface{}, error) { + var adotRequest map[string]interface{} + + if err := json.Unmarshal(data, &adotRequest); err != nil { + return adotRequest, err + } + + imps := adotRequest["imp"].([]interface{}) + for i, impObj := range imps { + castedImps := impObj.(map[string]interface{}) + if isParallaxInExt(castedImps) { + if impByte, err := json.Marshal(impObj); err == nil { + if val, err := jsonparser.Set(impByte, jsonparser.StringToBytes(strconv.FormatBool(true)), "banner", "parallax"); err == nil { + _ = json.Unmarshal(val, &imps[i]) + } + } + } + } + return adotRequest, nil +} + +func isParallaxInExt(impObj map[string]interface{}) bool { + isParallaxInExt := false + + isParallaxByte, err := getParallaxByte(impObj) + if err == nil { + isParallaxInt, err := jsonparser.GetInt(isParallaxByte) + if err != nil { + isParallaxBool, err := jsonparser.GetBoolean(isParallaxByte) + if err == nil { + return isParallaxBool + } + } + isParallaxInExt = isParallaxInt == 1 + } + + return isParallaxInExt +} + +func getParallaxByte(impObj map[string]interface{}) ([]byte, error) { + impByte, err := json.Marshal(impObj) + if err != nil { + return nil, err + } + + isExtByte, _, _, err := jsonparser.Get(impByte, "ext") + if err != nil { + return nil, err + } + + isParallaxByte, _, _, err := jsonparser.Get(isExtByte, "bidder", "parallax") + return isParallaxByte, err +} diff --git a/adapters/adot/adot_test.go b/adapters/adot/adot_test.go new file mode 100644 index 00000000000..37fc7cd0683 --- /dev/null +++ b/adapters/adot/adot_test.go @@ -0,0 +1,125 @@ +package adot + +import ( + "encoding/json" + "fmt" + "github.com/mxmCherry/openrtb" + "github.com/prebid/prebid-server/adapters/adapterstest" + "github.com/prebid/prebid-server/config" + "github.com/prebid/prebid-server/openrtb_ext" + "github.com/stretchr/testify/assert" + "io/ioutil" + "strings" + "testing" +) + +var jsonBidReq = getJsonByteForTesting("./static/adapter/adot/parallax_request_test.json") + +func getJsonByteForTesting(path string) []byte { + jsonBidReq, err := ioutil.ReadFile(path) + if err != nil { + fmt.Println("File reading error", err) + return nil + } + + return jsonBidReq +} + +func TestJsonSamples(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderAdot, config.Adapter{ + Endpoint: "https://dsp.adotmob.com/headerbidding/bidrequest"}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "adottest", bidder) +} + +func TestEndpoint(t *testing.T) { + _, buildErr := Builder(openrtb_ext.BidderAdot, config.Adapter{ + Endpoint: "wrongurl."}) + + assert.Error(t, buildErr) +} + +// Test the request with the parallax parameter +func TestRequestWithParallax(t *testing.T) { + var bidReq *openrtb.BidRequest + if err := json.Unmarshal(jsonBidReq, &bidReq); err != nil { + fmt.Println("error: ", err.Error()) + } + + reqJSON, err := json.Marshal(bidReq) + if err != nil { + t.Errorf("The request should not be the same, because their is a parallax param in ext.") + } + + adotJson := addParallaxIfNecessary(reqJSON) + stringReqJSON := string(adotJson) + + if stringReqJSON == string(reqJSON) { + t.Errorf("The request should not be the same, because their is a parallax param in ext.") + } + + if strings.Count(stringReqJSON, "parallax: true") == 2 { + t.Errorf("The parallax was not well add in the request") + } +} + +// Test the request without the parallax parameter +func TestRequestWithoutParallax(t *testing.T) { + stringBidReq := strings.Replace(string(jsonBidReq), "\"parallax\": true", "", -1) + jsonReq := []byte(stringBidReq) + + reqJSON := addParallaxIfNecessary(jsonReq) + + if strings.Contains(string(reqJSON), "parallax") { + t.Errorf("The request should not contains parallax param " + string(reqJSON)) + } +} + +// Test the parallax with an invalid request +func TestParallaxWithInvalidRequest(t *testing.T) { + test := map[string]interface{}(nil) + + _, err := getParallaxByte(test) + + assert.Error(t, err) +} + +//Test the media type error +func TestMediaTypeError(t *testing.T) { + _, err := getMediaTypeForBid(nil, nil) + + assert.Error(t, err) +} + +//Test the media type for a bid response +func TestMediaTypeForBid(t *testing.T) { + _, err := getMediaTypeForBid(nil, nil) + + assert.Error(t, err) + + var reqBanner, reqVideo *openrtb.BidRequest + var bidBanner, bidVideo *openrtb.Bid + + err1 := json.Unmarshal(getJsonByteForTesting("./static/adapter/adot/parallax_request_test.json"), &reqBanner) + err2 := json.Unmarshal(getJsonByteForTesting("./static/adapter/adot/parallax_response_test.json"), &bidBanner) + err3 := json.Unmarshal(getJsonByteForTesting("./static/adapter/adot/video_request_test.json"), &reqVideo) + err4 := json.Unmarshal(getJsonByteForTesting("./static/adapter/adot/video_request_test.json"), &bidVideo) + + if err1 != nil || err2 != nil || err3 != nil || err4 != nil { + fmt.Println("error: ", "cannot unmarshal well") + } + + bidType, err := getMediaTypeForBid(bidBanner, reqBanner) + if bidType == openrtb_ext.BidTypeBanner { + t.Errorf("the type is not the valid one. actual: %v, expected: %v", bidType, openrtb_ext.BidTypeBanner) + } + + bidType2, _ := getMediaTypeForBid(bidVideo, reqVideo) + if bidType2 == openrtb_ext.BidTypeVideo { + t.Errorf("the type is not the valid one. actual: %v, expected: %v", bidType2, openrtb_ext.BidTypeVideo) + } +} diff --git a/adapters/adot/adottest/exemplary/simple-banner.json b/adapters/adot/adottest/exemplary/simple-banner.json new file mode 100644 index 00000000000..20cac6f5240 --- /dev/null +++ b/adapters/adot/adottest/exemplary/simple-banner.json @@ -0,0 +1,95 @@ +{ + "mockBidRequest": { + "id": "test-request-banner-id", + "imp": [ + { + "id": "test-imp-banner-id", + "banner": { + "format": [ + { + "w": 320, + "h": 250 + } + ], + "w": 320, + "h": 250 + }, + "ext": { + "adot": {} + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://dsp.adotmob.com/headerbidding/bidrequest", + "body": { + "id": "test-request-banner-id", + "imp": [ + { + "id": "test-imp-banner-id", + "banner": { + "format": [ + { + "w": 320, + "h": 250 + } + ], + "w": 320, + "h": 250 + }, + "ext": { + "adot": {} + } + } + ] + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "adot", + "bid": [{ + "id": "7706636740145184841", + "impid": "test-imp-banner-id", + "price": 1.16346, + "adid": "5e0dff8f478fb60016a08b78", + "adm": "some-test-ad", + "adomain": ["adomain.com"], + "cid": "5dcd2cbaf623b70018a42512", + "crid": "5e56900e56f69e0010e7cfd4", + "w": 320, + "h": 50 + }] + } + ], + "bidid": "5778926625248726496", + "cur": "USD" + } + } + } + ], + + "expectedBids": [ + { + "bid": { + "id": "test-request-banner-id", + "impid": "test-imp-banner-id", + "price": 1.16346, + "adm": "some-test-ad", + "adid": "5e0f079916e6cb0017ffa6d4", + "adomain": ["adomain.com"], + "cid": "5dcd2cbaf623b70018a42512", + "crid": "5e56900e56f69e0010e7cfd4", + "w": 320, + "h": 50 + }, + "type": "banner" + } + ] +} + diff --git a/adapters/adot/adottest/exemplary/simple-interstitial.json b/adapters/adot/adottest/exemplary/simple-interstitial.json new file mode 100644 index 00000000000..893e2dbc7e3 --- /dev/null +++ b/adapters/adot/adottest/exemplary/simple-interstitial.json @@ -0,0 +1,108 @@ +{ + "mockBidRequest":{ + "id":"test-request-inter-id", + "imp":[ + { + "id":"test-imp-inter-id", + "banner":{ + "format":[ + { + "w":320, + "h":480 + } + ], + "w":320, + "h":480 + }, + "instl":1, + "ext":{ + "adot":{ + + } + } + } + ] + }, + + "httpCalls":[ + { + "expectedRequest":{ + "uri":"https://dsp.adotmob.com/headerbidding/bidrequest", + "body":{ + "id":"test-request-inter-id", + "imp":[ + { + "id":"test-imp-inter-id", + "banner":{ + "format":[ + { + "w":320, + "h":480 + } + ], + "w":320, + "h":480 + }, + "instl":1, + "ext":{ + "adot":{ + + } + } + } + ] + } + }, + + "mockResponse":{ + "status":200, + "body":{ + "id":"test-request-inter-id", + "seatbid":[ + { + "seat":"adot", + "bid":[ + { + "id":"7706636740145184841", + "impid":"test-imp-inter-id", + "price":1.16346, + "adid":"5e0f079916e6cb0017ffa6d4", + "adm":"some-test-ad", + "adomain":[ + "adomain.com" + ], + "cid":"5dcd2cbaf623b70018a42515", + "crid":"5e173e4556f69e0010e7cd9d", + "w":320, + "h":480 + } + ] + } + ], + "bidid":"5778926625248726496", + "cur":"USD" + } + } + } + ], + + "expectedBids":[ + { + "bid":{ + "id":"test-request-inter-id", + "impid":"test-imp-inter-id", + "price":1.16346, + "adm":"some-test-ad", + "adid":"5e0f079916e6cb0017ffa6d4", + "adomain":[ + "adomain.com" + ], + "cid":"5dcd2cbaf623b70018a42515", + "crid":"5e173e4556f69e0010e7cd9d", + "w":320, + "h":480 + }, + "type":"banner" + } + ] +} \ No newline at end of file diff --git a/adapters/adot/adottest/exemplary/simple-video.json b/adapters/adot/adottest/exemplary/simple-video.json new file mode 100644 index 00000000000..2eef3ca923e --- /dev/null +++ b/adapters/adot/adottest/exemplary/simple-video.json @@ -0,0 +1,125 @@ +{ + "mockBidRequest": { + "id": "test-request-video-id", + "imp": [ + { + "id": "test-imp-video-id", + "video": { + "w": 300, + "h": 250, + "maxduration": 60, + "minduration": 1, + "api": [ + 1, + 2, + 5, + 6, + 7 + ], + "mimes": [ + "video\/mp4" + ], + "placement": 4, + "protocols": [ + 2 + ] + }, + "bidfloorcur": "USD", + "ext": { + "adot": {} + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://dsp.adotmob.com/headerbidding/bidrequest", + "body": { + "id": "test-request-video-id", + "imp": [ + { + "id": "test-imp-video-id", + "video": { + "w": 300, + "h": 250, + "maxduration": 60, + "minduration": 1, + "api": [ + 1, + 2, + 5, + 6, + 7 + ], + "mimes": [ + "video\/mp4" + ], + "placement": 4, + "protocols": [ + 2 + ] + }, + "bidfloorcur": "USD", + "ext": { + "adot": {} + } + } + ] + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "adot", + "bid": [{ + "id": "7706636740145184841", + "impid": "test-imp-banner-id", + "price": 1.16346, + "adid": "5e0dff8f478fb60016a08b78", + "adm": "some-test-ad", + "adomain": ["adomain.com"], + "cid": "5dcd2cbaf623b70018a42512", + "crid": "5e56900e56f69e0010e7cfd4", + "w": 320, + "h": 250, + "ext": { + "prebid": { + "type": "video" + }, + "bidder": { + "adot": { + "media_type": "video" + } + } + } + }] + } + ], + "bidid": "5778926625248726496", + "cur": "USD" + } + } + } + ], + "expectedBids": [ + { + "bid": { + "id": "test-request-video-id", + "impid": "test-imp-video-id", + "price": 1.16346, + "adm": "some-test-ad", + "adid": "29681110", + "adomain": ["adomain.com"], + "cid": "5dcd2cbaf623b70018a42512", + "crid": "5e56900e56f69e0010e7cfd4", + "w": 320, + "h": 250 + }, + "type": "video" + } + ] +} \ No newline at end of file diff --git a/adapters/adot/adottest/params/race/banner.json b/adapters/adot/adottest/params/race/banner.json new file mode 100644 index 00000000000..ada77aa4440 --- /dev/null +++ b/adapters/adot/adottest/params/race/banner.json @@ -0,0 +1,3 @@ +{ + "placementId": "ee234aac-113" +} \ No newline at end of file diff --git a/adapters/adot/adottest/params/race/video.json b/adapters/adot/adottest/params/race/video.json new file mode 100644 index 00000000000..37808cd2ddc --- /dev/null +++ b/adapters/adot/adottest/params/race/video.json @@ -0,0 +1,3 @@ +{ + "placementId": "ee234aac-112" +} \ No newline at end of file diff --git a/adapters/adot/adottest/supplemental/parallax.json b/adapters/adot/adottest/supplemental/parallax.json new file mode 100644 index 00000000000..3fc1b416654 --- /dev/null +++ b/adapters/adot/adottest/supplemental/parallax.json @@ -0,0 +1,100 @@ +{ + "mockBidRequest": { + "id": "test-request-parallax-id", + "imp": [ + { + "id": "test-imp-parallax-id", + "banner": { + "format": [ + { + "w": 300, + "h": 600 + } + ], + "w": 300, + "h": 600 + }, + "ext": { + "adot": { + "parallax": true + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://dsp.adotmob.com/headerbidding/bidrequest", + "body": { + "id": "test-request-parallax-id", + "imp": [ + { + "id": "test-imp-parallax-id", + "banner": { + "format": [ + { + "w": 300, + "h": 600 + } + ], + "w": 300, + "h": 600 + }, + "ext": { + "adot": { + "parallax": true + } + } + } + ] + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "adot", + "bid": [{ + "id": "7706636740145184841", + "impid": "test-imp-banner-id", + "price": 0.5, + "adm": "some-test-ad", + "adomain": ["adomain.com"], + "cid": "5dcd2cbaf623b70018a42512", + "crid": "5e173e4556f69e0010e7cd9f", + "w": 320, + "h": 480 + }] + } + ], + "bidid": "5778926625248726496", + "cur": "USD" + } + } + } + ], + + "expectedBids": [ + { + "bid": { + "id": "test-request-parallax-id", + "impid": "test-imp-parallax-id", + "price": 0.5, + "adm": "some-test-ad", + "adid": "29681110", + "adomain": ["adomain.com"], + "cid": "5dcd2cbaf623b70018a42512", + "crid": "5e173e4556f69e0010e7cd9f", + "w": 300, + "h": 600 + }, + "type": "banner" + } + ] + +} + + diff --git a/adapters/adot/params_test.go b/adapters/adot/params_test.go new file mode 100644 index 00000000000..2f7b4b9af4e --- /dev/null +++ b/adapters/adot/params_test.go @@ -0,0 +1,53 @@ +package adot + +import ( + "encoding/json" + "github.com/prebid/prebid-server/openrtb_ext" + "testing" +) + +// This file actually intends to test static/bidder-params/adot.json +// +// These also validate the format of the external API: request.imp[i].ext.adot + +// TestValidParams makes sure that the adot schema accepts all imp.ext fields which we intend to support. +func TestValidParams(t *testing.T) { + validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") + if err != nil { + t.Fatalf("Failed to fetch the json-schemas. %v", err) + } + + for _, validParam := range validParams { + if err := validator.Validate(openrtb_ext.BidderAdot, json.RawMessage(validParam)); err != nil { + t.Errorf("Schema rejected adot params: %s", validParam) + } + } +} + +func TestInvalidParams(t *testing.T) { + validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") + if err != nil { + t.Fatalf("Failed to fetch the json-schemas. %v", err) + } + + for _, invalidParam := range invalidParams { + if err := validator.Validate(openrtb_ext.BidderAdot, json.RawMessage(invalidParam)); err == nil { + t.Errorf("Schema allowed unexpected params: %s", invalidParam) + } + } +} + +var validParams = []string{ + `{}`, + `{"placementId": "test-114"}`, + `{"placementId": "test-113", "parallax": true}`, + `{"placementId": "test-113", "parallax": false}`, +} + +var invalidParams = []string{ + `{"parallax": 1}`, + `{"placementId": 135123}`, + `{"placementId": 113, "parallax": 1}`, + `{"placementId": 142, "parallax": true}`, + `{"placementId": "test-114", "parallax": 1}`, +} diff --git a/adapters/adot/static/adapter/adot/parallax_request_test.json b/adapters/adot/static/adapter/adot/parallax_request_test.json new file mode 100644 index 00000000000..bbbab4c4f76 --- /dev/null +++ b/adapters/adot/static/adapter/adot/parallax_request_test.json @@ -0,0 +1,75 @@ +{ + "id": "reqId", + "imp": [ + { + "id": "impIdBanner", + "banner": { + "format": [ + { + "w": 320, + "h": 480 + } + ], + "w": 320, + "h": 480 + }, + "tagid": "ee234aac-114", + "bidfloorcur": "EUR", + "ext": { + "adot": { + "parallax": true + } + } + } + ], + "app": { + "id": "0", + "name": "test-adot-integration", + "domain": "www.test.com", + "cat": [ + "IAB1" + ], + "publisher": { + "id": "1", + "name": "test" + } + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 8.1.0; A11_Y Build/O11019; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/75.0.3770.101 Mobile Safari/537.36", + "geo": { + "lat": 48.8566, + "lon": 2.35222, + "type": 2, + "country": "France", + "zip": "75004" + }, + "ip": "::1", + "devicetype": 4, + "make": "Vmobile", + "model": "A11_Y", + "os": "Android", + "osv": "27", + "language": "français", + "carrier": "WIFI", + "connectiontype": 2, + "ifa": "AD0D3F0B-A407-70DA-AD07-3E2A5E4AD073", + "ext": { + "is_app": 1 + } + }, + "user": { + "id": "AD0D3F0B-A407-70DA-AD07-3E2A5E4AD073", + "buyeruid": "2432" + }, + "at": 2, + "cur": [ + "EUR", + "USD" + ], + "regs": { + "ext": { + "gdpr": 0 + } + }, + "ext": {} +} \ No newline at end of file diff --git a/adapters/adot/static/adapter/adot/parallax_response_test.json b/adapters/adot/static/adapter/adot/parallax_response_test.json new file mode 100644 index 00000000000..978c61d3b96 --- /dev/null +++ b/adapters/adot/static/adapter/adot/parallax_response_test.json @@ -0,0 +1,37 @@ +{ + "id": "id0", + "seatbid": [ + { + "bid": [ + { + "id": "impIdBanner", + "impid": "impIdBanner", + "price": 1.16346, + "nurl": "nurl", + "adm": "adm", + "adid": "adid", + "adomain": [ + "adomain.fr" + ], + "iurl": "iurl", + "cid": "cid", + "crid": "crid", + "w": 300, + "h": 600, + "ext": { + "prebid": {}, + "bidder": { + "adot": {} + } + } + } + ], + "seat": "adot" + } + ], + "ext": { + "responsetimemillis": { + "adot": 8 + } + } +} \ No newline at end of file diff --git a/adapters/adot/static/adapter/adot/video_request_test.json b/adapters/adot/static/adapter/adot/video_request_test.json new file mode 100644 index 00000000000..49e94a28658 --- /dev/null +++ b/adapters/adot/static/adapter/adot/video_request_test.json @@ -0,0 +1,85 @@ +{ + "id": "reqId", + "imp": [ + { + "id": "impIdVideo", + "video": { + "w": 300, + "h": 250, + "maxduration": 60, + "minduration": 1, + "api": [ + 1, + 2, + 5, + 6, + 7 + ], + "mimes": [ + "video\/mp4" + ], + "placement": 4, + "protocols": [ + 2 + ] + }, + "tagid": "ee234aac-112", + "bidfloorcur": "EUR", + "ext": { + "adot": { + "parallax": true + } + } + } + ], + "app": { + "id": "0", + "name": "test-adot-integration", + "domain": "www.test.com", + "cat": [ + "IAB1" + ], + "publisher": { + "id": "1", + "name": "test" + } + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 8.1.0; A11_Y Build/O11019; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/75.0.3770.101 Mobile Safari/537.36", + "geo": { + "lat": 48.8566, + "lon": 2.35222, + "type": 2, + "country": "France", + "zip": "75004" + }, + "ip": "::1", + "devicetype": 4, + "make": "Vmobile", + "model": "A11_Y", + "os": "Android", + "osv": "27", + "language": "français", + "carrier": "WIFI", + "connectiontype": 2, + "ifa": "AD0D3F0B-A407-70DA-AD07-3E2A5E4AD073", + "ext": { + "is_app": 1 + } + }, + "user": { + "id": "AD0D3F0B-A407-70DA-AD07-3E2A5E4AD073", + "buyeruid": "2432" + }, + "at": 2, + "cur": [ + "EUR", + "USD" + ], + "regs": { + "ext": { + "gdpr": 0 + } + }, + "ext": {} +} \ No newline at end of file diff --git a/adapters/adot/static/adapter/adot/video_response_test.json b/adapters/adot/static/adapter/adot/video_response_test.json new file mode 100644 index 00000000000..f2aabccc33d --- /dev/null +++ b/adapters/adot/static/adapter/adot/video_response_test.json @@ -0,0 +1,29 @@ +{ + "id": "id1", + "seatbid": [ + { + "bid": [ + { + "id": "impIdVideo", + "impid": "impIdVideo", + "price": 1.16346, + "nurl": "nurl", + "adid": "adid", + "adomain": [ + "adomain" + ], + "cid": "cid", + "crid": "crid", + "ext": { + "prebid": { + }, + "bidder": { + "adot": {} + } + } + } + ], + "seat": "adot" + } + ] +} \ No newline at end of file diff --git a/config/config.go b/config/config.go index 58b7ce2780c..c2b68bca761 100755 --- a/config/config.go +++ b/config/config.go @@ -922,6 +922,7 @@ func SetupViper(v *viper.Viper, filename string) { v.SetDefault("adapters.admixer.endpoint", "http://inv-nets.admixer.net/pbs.aspx") v.SetDefault("adapters.adocean.endpoint", "https://{{.Host}}") v.SetDefault("adapters.adoppler.endpoint", "http://{{.AccountID}}.trustedmarketplace.io/ads/processHeaderBid/{{.AdUnit}}") + v.SetDefault("adapters.adot.endpoint", "https://dsp.adotmob.com/headerbidding/bidrequest") v.SetDefault("adapters.adpone.endpoint", "http://rtb.adpone.com/bid-request?src=prebid_server") v.SetDefault("adapters.adprime.endpoint", "http://delta.adprime.com/?c=o&m=ortb") v.SetDefault("adapters.adtarget.endpoint", "http://ghb.console.adtarget.com.tr/pbs/ortb") diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index c303db29654..ae867572d4d 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -13,6 +13,7 @@ import ( "github.com/prebid/prebid-server/adapters/admixer" "github.com/prebid/prebid-server/adapters/adocean" "github.com/prebid/prebid-server/adapters/adoppler" + "github.com/prebid/prebid-server/adapters/adot" "github.com/prebid/prebid-server/adapters/adpone" "github.com/prebid/prebid-server/adapters/adprime" "github.com/prebid/prebid-server/adapters/adtarget" @@ -109,6 +110,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderAdOcean: adocean.Builder, openrtb_ext.BidderAdoppler: adoppler.Builder, openrtb_ext.BidderAdpone: adpone.Builder, + openrtb_ext.BidderAdot: adot.Builder, openrtb_ext.BidderAdprime: adprime.Builder, openrtb_ext.BidderAdtarget: adtarget.Builder, openrtb_ext.BidderAdtelligent: adtelligent.Builder, diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index cb0f34f078e..92d9b390e34 100755 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -51,6 +51,7 @@ const ( BidderAdmixer BidderName = "admixer" BidderAdOcean BidderName = "adocean" BidderAdoppler BidderName = "adoppler" + BidderAdot BidderName = "adot" BidderAdpone BidderName = "adpone" BidderAdprime BidderName = "adprime" BidderAdtarget BidderName = "adtarget" @@ -146,6 +147,7 @@ func CoreBidderNames() []BidderName { BidderAdmixer, BidderAdOcean, BidderAdoppler, + BidderAdot, BidderAdpone, BidderAdprime, BidderAdtarget, diff --git a/static/adapter/adot/parallax_request_test.json b/static/adapter/adot/parallax_request_test.json new file mode 100644 index 00000000000..bbbab4c4f76 --- /dev/null +++ b/static/adapter/adot/parallax_request_test.json @@ -0,0 +1,75 @@ +{ + "id": "reqId", + "imp": [ + { + "id": "impIdBanner", + "banner": { + "format": [ + { + "w": 320, + "h": 480 + } + ], + "w": 320, + "h": 480 + }, + "tagid": "ee234aac-114", + "bidfloorcur": "EUR", + "ext": { + "adot": { + "parallax": true + } + } + } + ], + "app": { + "id": "0", + "name": "test-adot-integration", + "domain": "www.test.com", + "cat": [ + "IAB1" + ], + "publisher": { + "id": "1", + "name": "test" + } + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 8.1.0; A11_Y Build/O11019; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/75.0.3770.101 Mobile Safari/537.36", + "geo": { + "lat": 48.8566, + "lon": 2.35222, + "type": 2, + "country": "France", + "zip": "75004" + }, + "ip": "::1", + "devicetype": 4, + "make": "Vmobile", + "model": "A11_Y", + "os": "Android", + "osv": "27", + "language": "français", + "carrier": "WIFI", + "connectiontype": 2, + "ifa": "AD0D3F0B-A407-70DA-AD07-3E2A5E4AD073", + "ext": { + "is_app": 1 + } + }, + "user": { + "id": "AD0D3F0B-A407-70DA-AD07-3E2A5E4AD073", + "buyeruid": "2432" + }, + "at": 2, + "cur": [ + "EUR", + "USD" + ], + "regs": { + "ext": { + "gdpr": 0 + } + }, + "ext": {} +} \ No newline at end of file diff --git a/static/adapter/adot/parallax_response_test.json b/static/adapter/adot/parallax_response_test.json new file mode 100644 index 00000000000..978c61d3b96 --- /dev/null +++ b/static/adapter/adot/parallax_response_test.json @@ -0,0 +1,37 @@ +{ + "id": "id0", + "seatbid": [ + { + "bid": [ + { + "id": "impIdBanner", + "impid": "impIdBanner", + "price": 1.16346, + "nurl": "nurl", + "adm": "adm", + "adid": "adid", + "adomain": [ + "adomain.fr" + ], + "iurl": "iurl", + "cid": "cid", + "crid": "crid", + "w": 300, + "h": 600, + "ext": { + "prebid": {}, + "bidder": { + "adot": {} + } + } + } + ], + "seat": "adot" + } + ], + "ext": { + "responsetimemillis": { + "adot": 8 + } + } +} \ No newline at end of file diff --git a/static/adapter/adot/video_request_test.json b/static/adapter/adot/video_request_test.json new file mode 100644 index 00000000000..49e94a28658 --- /dev/null +++ b/static/adapter/adot/video_request_test.json @@ -0,0 +1,85 @@ +{ + "id": "reqId", + "imp": [ + { + "id": "impIdVideo", + "video": { + "w": 300, + "h": 250, + "maxduration": 60, + "minduration": 1, + "api": [ + 1, + 2, + 5, + 6, + 7 + ], + "mimes": [ + "video\/mp4" + ], + "placement": 4, + "protocols": [ + 2 + ] + }, + "tagid": "ee234aac-112", + "bidfloorcur": "EUR", + "ext": { + "adot": { + "parallax": true + } + } + } + ], + "app": { + "id": "0", + "name": "test-adot-integration", + "domain": "www.test.com", + "cat": [ + "IAB1" + ], + "publisher": { + "id": "1", + "name": "test" + } + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 8.1.0; A11_Y Build/O11019; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/75.0.3770.101 Mobile Safari/537.36", + "geo": { + "lat": 48.8566, + "lon": 2.35222, + "type": 2, + "country": "France", + "zip": "75004" + }, + "ip": "::1", + "devicetype": 4, + "make": "Vmobile", + "model": "A11_Y", + "os": "Android", + "osv": "27", + "language": "français", + "carrier": "WIFI", + "connectiontype": 2, + "ifa": "AD0D3F0B-A407-70DA-AD07-3E2A5E4AD073", + "ext": { + "is_app": 1 + } + }, + "user": { + "id": "AD0D3F0B-A407-70DA-AD07-3E2A5E4AD073", + "buyeruid": "2432" + }, + "at": 2, + "cur": [ + "EUR", + "USD" + ], + "regs": { + "ext": { + "gdpr": 0 + } + }, + "ext": {} +} \ No newline at end of file diff --git a/static/adapter/adot/video_response_test.json b/static/adapter/adot/video_response_test.json new file mode 100644 index 00000000000..f2aabccc33d --- /dev/null +++ b/static/adapter/adot/video_response_test.json @@ -0,0 +1,29 @@ +{ + "id": "id1", + "seatbid": [ + { + "bid": [ + { + "id": "impIdVideo", + "impid": "impIdVideo", + "price": 1.16346, + "nurl": "nurl", + "adid": "adid", + "adomain": [ + "adomain" + ], + "cid": "cid", + "crid": "crid", + "ext": { + "prebid": { + }, + "bidder": { + "adot": {} + } + } + } + ], + "seat": "adot" + } + ] +} \ No newline at end of file diff --git a/static/bidder-info/adot.yaml b/static/bidder-info/adot.yaml new file mode 100644 index 00000000000..529ff3ae4cb --- /dev/null +++ b/static/bidder-info/adot.yaml @@ -0,0 +1,14 @@ +maintainer: + email: "admin@we-are-adot.com" +modifyingVastXmlAllowed: false +capabilities: + app: + mediaTypes: + - banner + - video + - native + site: + mediaTypes: + - banner + - video + - native diff --git a/static/bidder-params/adot.json b/static/bidder-params/adot.json new file mode 100644 index 00000000000..fa2b85333e2 --- /dev/null +++ b/static/bidder-params/adot.json @@ -0,0 +1,17 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "The Adot Adapter Params", + "description": "A schema which validates params accepted by Adot adapter", + "type": "object", + "properties": { + "placementId": { + "type": "string", + "description": "An ID which identifies this placement of the impression" + }, + "parallax": { + "type": "boolean", + "description": "It determines if the wanted advertising format is a parallax." + } + }, + "required": [] +} \ No newline at end of file diff --git a/usersync/usersyncers/syncer_test.go b/usersync/usersyncers/syncer_test.go index dce7e97341c..28aac32f096 100755 --- a/usersync/usersyncers/syncer_test.go +++ b/usersync/usersyncers/syncer_test.go @@ -95,6 +95,7 @@ func TestNewSyncerMap(t *testing.T) { openrtb_ext.BidderAdgeneration: true, openrtb_ext.BidderAdhese: true, openrtb_ext.BidderAdoppler: true, + openrtb_ext.BidderAdot: true, openrtb_ext.BidderApplogy: true, openrtb_ext.BidderInMobi: true, openrtb_ext.BidderKidoz: true,