diff --git a/adapters/nanointeractive/nanointeractive.go b/adapters/nanointeractive/nanointeractive.go new file mode 100644 index 00000000000..72832893af1 --- /dev/null +++ b/adapters/nanointeractive/nanointeractive.go @@ -0,0 +1,172 @@ +package nanointeractive + +import ( + "encoding/json" + "fmt" + "github.com/mxmCherry/openrtb" + "github.com/prebid/prebid-server/adapters" + "github.com/prebid/prebid-server/errortypes" + "github.com/prebid/prebid-server/openrtb_ext" + "net/http" +) + +type NanoInteractiveAdapter struct { + endpoint string +} + +func (a *NanoInteractiveAdapter) Name() string { + return "Nano" +} + +func (a *NanoInteractiveAdapter) SkipNoCookies() bool { + return false +} + +func (a *NanoInteractiveAdapter) MakeRequests(bidRequest *openrtb.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { + + var errs []error + var validImps []openrtb.Imp + + var adapterRequests []*adapters.RequestData + var referer string = "" + + for i := 0; i < len(bidRequest.Imp); i++ { + + ref, err := checkImp(&bidRequest.Imp[i]) + + // If the parsing is failed, remove imp and add the error. + if err != nil { + errs = append(errs, err) + continue + } + if referer == "" && ref != "" { + referer = ref + } + validImps = append(validImps, bidRequest.Imp[i]) + } + + if len(validImps) == 0 { + errs = append(errs, fmt.Errorf("no impressions in the bid request")) + return nil, errs + } + + // set referer origin + if referer != "" { + if bidRequest.Site == nil { + bidRequest.Site = &openrtb.Site{} + } + bidRequest.Site.Ref = referer + } + + bidRequest.Imp = validImps + + reqJSON, err := json.Marshal(bidRequest) + if err != nil { + errs = append(errs, err) + return nil, errs + } + + headers := http.Header{} + headers.Add("Content-Type", "application/json;charset=utf-8") + headers.Add("Accept", "application/json") + headers.Add("x-openrtb-version", "2.5") + if bidRequest.Device != nil { + headers.Add("User-Agent", bidRequest.Device.UA) + headers.Add("X-Forwarded-For", bidRequest.Device.IP) + } + if bidRequest.Site != nil { + headers.Add("Referer", bidRequest.Site.Page) + } + + // set user's cookie + if bidRequest.User != nil && bidRequest.User.BuyerUID != "" { + headers.Add("Cookie", "Nano="+bidRequest.User.BuyerUID) + } + + adapterRequests = append(adapterRequests, &adapters.RequestData{ + Method: "POST", + Uri: a.endpoint, + Body: reqJSON, + Headers: headers, + }) + + return adapterRequests, errs +} + +func (a *NanoInteractiveAdapter) MakeBids( + internalRequest *openrtb.BidRequest, + externalRequest *adapters.RequestData, + response *adapters.ResponseData) (*adapters.BidderResponse, []error) { + + if response.StatusCode == http.StatusNoContent { + return nil, nil + } else if response.StatusCode == http.StatusBadRequest { + return nil, []error{adapters.BadInput("Invalid request.")} + } else if response.StatusCode != http.StatusOK { + return nil, []error{&errortypes.BadServerResponse{ + Message: fmt.Sprintf("unexpected HTTP status %d.", response.StatusCode), + }} + } + + var openRtbBidResponse openrtb.BidResponse + + if err := json.Unmarshal(response.Body, &openRtbBidResponse); err != nil { + return nil, []error{&errortypes.BadServerResponse{ + Message: fmt.Sprintf("bad server body response"), + }} + } + + bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(openRtbBidResponse.SeatBid[0].Bid)) + bidResponse.Currency = openRtbBidResponse.Cur + + sb := openRtbBidResponse.SeatBid[0] + for i := 0; i < len(sb.Bid); i++ { + if !(sb.Bid[i].Price > 0) { + continue + } + bid := sb.Bid[i] + bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ + Bid: &bid, + BidType: openrtb_ext.BidTypeBanner, + }) + } + return bidResponse, nil +} + +func checkImp(imp *openrtb.Imp) (string, error) { + // We support only banner impression + if imp.Banner == nil { + return "", fmt.Errorf("invalid MediaType. NanoInteractive only supports Banner type. ImpID=%s", imp.ID) + } + + var bidderExt adapters.ExtImpBidder + if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil { + return "", fmt.Errorf("ext not provided; ImpID=%s", imp.ID) + } + + var nanoExt openrtb_ext.ExtImpNanoInteractive + if err := json.Unmarshal(bidderExt.Bidder, &nanoExt); err != nil { + return "", fmt.Errorf("ext.bidder not provided; ImpID=%s", imp.ID) + } + if nanoExt.Pid == "" { + return "", fmt.Errorf("pid is empty; ImpID=%s", imp.ID) + } + + if nanoExt.Ref != "" { + return string(nanoExt.Ref), nil + } + + return "", nil +} + +func NewNanoIneractiveBidder(endpoint string) *NanoInteractiveAdapter { + return &NanoInteractiveAdapter{ + endpoint: endpoint, + } +} + +func NewNanoInteractiveAdapter(uri string) *NanoInteractiveAdapter { + return &NanoInteractiveAdapter{ + endpoint: uri, + } +} diff --git a/adapters/nanointeractive/nanointeractive_test.go b/adapters/nanointeractive/nanointeractive_test.go new file mode 100644 index 00000000000..fa7069a5da3 --- /dev/null +++ b/adapters/nanointeractive/nanointeractive_test.go @@ -0,0 +1,10 @@ +package nanointeractive + +import ( + "github.com/prebid/prebid-server/adapters/adapterstest" + "testing" +) + +func TestJsonSamples(t *testing.T) { + adapterstest.RunJSONBidderTest(t, "nanointeractivetest", NewNanoIneractiveBidder("https://ad.audiencemanager.de/hbs")) +} diff --git a/adapters/nanointeractive/nanointeractivetest/exemplary/simple-banner.json b/adapters/nanointeractive/nanointeractivetest/exemplary/simple-banner.json new file mode 100644 index 00000000000..20cc70b6785 --- /dev/null +++ b/adapters/nanointeractive/nanointeractivetest/exemplary/simple-banner.json @@ -0,0 +1,90 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [{"w": 300, "h": 250}] + }, + "ext": { + "bidder": { + "pid": "58bfec94eb0a1916fa380163" + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://ad.audiencemanager.de/hbs", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [{ "w": 300,"h": 250} + ] + }, + "ext": { + "bidder": { + "pid": "58bfec94eb0a1916fa380163" + } + } + } + ] + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "nanointeractive", + "bid": [{ + "id": "1", + "impid": "test-imp-id", + "price": 0.4580126, + "adm": "", + "adid": "test_ad_id", + "adomain": ["audiencemanager.de"], + "cid": "test_cid", + "crid": "test_banner_crid", + "h": 250, + "w": 300 + }] + } + ], + "bidid": "5a7789eg2662b524d8d7264a96", + "cur": "EUR" + } + } + } + ], + + "expectedBids": [ + { + "bid": { + "id": "1", + "impid": "test-imp-id", + "price": 0.4580126, + "adm": "", + "adid": "test_ad_id", + "adomain": ["yahoo.com"], + "cid": "test_cid", + "crid": "test_banner_crid", + "h": 250, + "w": 300 + }, + "ext": { + "prebid": { + "type": "banner" + } + } + } + ] +} diff --git a/adapters/nanointeractive/nanointeractivetest/params/race/banner.json b/adapters/nanointeractive/nanointeractivetest/params/race/banner.json new file mode 100644 index 00000000000..bb35ea8488a --- /dev/null +++ b/adapters/nanointeractive/nanointeractivetest/params/race/banner.json @@ -0,0 +1,3 @@ +{ + "pid": "58bfec94eb0a1916fa380163" +} diff --git a/adapters/nanointeractive/nanointeractivetest/supplemental/bad_response.json b/adapters/nanointeractive/nanointeractivetest/supplemental/bad_response.json new file mode 100644 index 00000000000..587c952a042 --- /dev/null +++ b/adapters/nanointeractive/nanointeractivetest/supplemental/bad_response.json @@ -0,0 +1,63 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "pid": "213" + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://ad.audiencemanager.de/hbs", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "pid": "213" + } + } + } + ] + } + }, + "mockResponse": { + "status": 200, + "body": "{\"id\"data.lost" + } + } + ], + + "expectedMakeBidsErrors": [ + { + "value": "bad server body response", + "comparison": "literal" + } + ] +} diff --git a/adapters/nanointeractive/nanointeractivetest/supplemental/invalid-params.json b/adapters/nanointeractive/nanointeractivetest/supplemental/invalid-params.json new file mode 100644 index 00000000000..631dc99e5a8 --- /dev/null +++ b/adapters/nanointeractive/nanointeractivetest/supplemental/invalid-params.json @@ -0,0 +1,81 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id-1", + "banner": {}, + "ext": { + "bidder": {} + } + }, + { + "id": "test-imp-id-2", + "banner": { + "format": [{"w": 300, "h": 250}] + }, + "ext": { + + } + }, + { + "id": "test-imp-id-3", + "banner": { + "format": [{"w": 300, "h": 250}] + } + }, + { + "id": "test-imp-id-4", + "video": {}, + "ext": { + "bidder": {} + } + }, + { + "id": "test-imp-id-5", + "audio": { + "startdelay": 0, + "api": [] + }, + "ext": { + "bidder": {} + } + } + ], + "site": { + "id": "siteID", + "publisher": { + "id": "1234" + } + }, + "device": { + "os": "android" + } + }, + "expectedMakeRequestsErrors": [ + { + "value": "pid is empty; ImpID=test-imp-id-1", + "comparison": "literal" + }, + { + "value": "ext.bidder not provided; ImpID=test-imp-id-2", + "comparison": "literal" + }, + { + "value": "ext not provided; ImpID=test-imp-id-3", + "comparison": "literal" + }, + { + "value": "invalid MediaType. NanoInteractive only supports Banner type. ImpID=test-imp-id-4", + "comparison": "literal" + }, + { + "value": "invalid MediaType. NanoInteractive only supports Banner type. ImpID=test-imp-id-5", + "comparison": "literal" + }, + { + "value": "no impressions in the bid request", + "comparison": "literal" + } + ] +} diff --git a/adapters/nanointeractive/nanointeractivetest/supplemental/multi-param.json b/adapters/nanointeractive/nanointeractivetest/supplemental/multi-param.json new file mode 100644 index 00000000000..27e7bec1f5f --- /dev/null +++ b/adapters/nanointeractive/nanointeractivetest/supplemental/multi-param.json @@ -0,0 +1,151 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [{"w": 300, "h": 250}] + }, + "ext": { + "bidder": { + "pid": "58bfec94eb0a1916fa380163", + "ref": "https://nanointeractive.com" + } + } + }, + { + "id": "test-imp-id2", + "banner": { + "format": [{"w": 300, "h": 250}] + }, + "ext": { + "bidder": { + "pid": "58bfec94eb0a1916fa380163", + "nq": ["search query"], + "category": "Automotive", + "subId": "a23", + "ref": "https://nanointeractive.com" + } + } + } + ], + "device": { + "ip": "127.0.0.1", + "ua": "user_agent" + }, + "user": { + "buyeruid": "userId" + } + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://ad.audiencemanager.de/hbs", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [{ "w": 300,"h": 250} + ] + }, + "ext": { + "bidder": { + "pid": "58bfec94eb0a1916fa380163", + "ref": "https://nanointeractive.com" + } + } + }, + { + "id": "test-imp-id2", + "banner": { + "format": [{ "w": 300,"h": 250} + ] + }, + "ext": { + "bidder": { + "pid": "58bfec94eb0a1916fa380163", + "nq": ["search query"], + "category": "Automotive", + "subId": "a23", + "ref": "https://nanointeractive.com" + } + } + } + ], + "site": { + "ref": "https://nanointeractive.com" + }, + "device": { + "ip": "127.0.0.1", + "ua": "user_agent" + }, + "user": { + "buyeruid": "userId" + } + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "nanointeractive", + "bid": [{ + "id": "1", + "impid": "test-imp-id", + "price": 0.4580126, + "adm": "", + "adid": "test_ad_id", + "adomain": ["audiencemanager.de"], + "cid": "test_cid", + "crid": "test_banner_crid", + "h": 250, + "w": 300 + },{ + "id": "2", + "impid": "test-imp-id2", + "price": 0, + "adm": "", + "adid": "test_ad_id", + "adomain": ["audiencemanager.de"], + "cid": "test_cid", + "crid": "test_banner_crid", + "h": 250, + "w": 300 + }] + } + ], + "bidid": "5a7789eg2662b524d8d7264a96", + "cur": "EUR" + } + } + } + ], + + "expectedBids": [ + { + "bid": { + "id": "1", + "impid": "test-imp-id", + "price": 0.4580126, + "adm": "", + "adid": "test_ad_id", + "adomain": ["yahoo.com"], + "cid": "test_cid", + "crid": "test_banner_crid", + "h": 250, + "w": 300 + }, + "ext": { + "prebid": { + "type": "banner" + } + } + } + ] +} diff --git a/adapters/nanointeractive/nanointeractivetest/supplemental/status_204.json b/adapters/nanointeractive/nanointeractivetest/supplemental/status_204.json new file mode 100644 index 00000000000..ed4d8ff38b8 --- /dev/null +++ b/adapters/nanointeractive/nanointeractivetest/supplemental/status_204.json @@ -0,0 +1,58 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "pid": "123" + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://ad.audiencemanager.de/hbs", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "pid": "123" + } + } + } + ] + } + }, + "mockResponse": { + "status": 204, + "body": {} + } + } + ], + + "expectedBidResponses": [] +} diff --git a/adapters/nanointeractive/nanointeractivetest/supplemental/status_400.json b/adapters/nanointeractive/nanointeractivetest/supplemental/status_400.json new file mode 100644 index 00000000000..f02bd478656 --- /dev/null +++ b/adapters/nanointeractive/nanointeractivetest/supplemental/status_400.json @@ -0,0 +1,63 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "pid": "123" + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://ad.audiencemanager.de/hbs", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "pid": "123" + } + } + } + ] + } + }, + "mockResponse": { + "status": 400, + "body": {} + } + } + ], + + "expectedMakeBidsErrors": [ + { + "value": "Invalid request.", + "comparison": "literal" + } + ] +} diff --git a/adapters/nanointeractive/nanointeractivetest/supplemental/status_418.json b/adapters/nanointeractive/nanointeractivetest/supplemental/status_418.json new file mode 100644 index 00000000000..b7ed65da2af --- /dev/null +++ b/adapters/nanointeractive/nanointeractivetest/supplemental/status_418.json @@ -0,0 +1,63 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "pid": "123" + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://ad.audiencemanager.de/hbs", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "pid": "123" + } + } + } + ] + } + }, + "mockResponse": { + "status": 418, + "body": {} + } + } + ], + + "expectedMakeBidsErrors": [ + { + "value": "unexpected HTTP status 418.", + "comparison": "literal" + } + ] +} diff --git a/adapters/nanointeractive/params_test.go b/adapters/nanointeractive/params_test.go new file mode 100644 index 00000000000..b290f3d94b1 --- /dev/null +++ b/adapters/nanointeractive/params_test.go @@ -0,0 +1,63 @@ +package nanointeractive + +import ( + "encoding/json" + "testing" + + "github.com/prebid/prebid-server/openrtb_ext" +) + +// This file actually intends to test static/bidder-params/nanointeractive.json +// +// These also validate the format of the external API: request.imp[i].ext.nanointeracive + +// TestValidParams makes sure that the NanoInteractive 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.BidderNanoInteractive, json.RawMessage(validParam)); err != nil { + t.Errorf("Schema rejected NanoInteractive params: %s", validParam) + } + } +} + +// TestInvalidParams makes sure that the Marsmedia schema rejects all the imp.ext fields we don't support. +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.BidderNanoInteractive, json.RawMessage(invalidParam)); err == nil { + t.Errorf("Schema allowed unexpected params: %s", invalidParam) + } + } +} + +var validParams = []string{ + `{"pid": "dafad098"}`, + `{"pid":"dfasfda","nq":["search query"]}`, + `{"pid":"dfasfda","nq":["search query"],"subId":"any string value","category":"any string value"}`, +} + +var invalidParams = []string{ + `{"pid":123}`, + `{"pid":"12323","nq":"search query not an array"}`, + `{"pid":"12323","category":1}`, + `{"pid":"12323","subId":23}`, + ``, + `null`, + `true`, + `9`, + `1.2`, + `[]`, + `{}`, + `placementId`, + `zone`, + `zoneId`, +} diff --git a/adapters/nanointeractive/usersync.go b/adapters/nanointeractive/usersync.go new file mode 100644 index 00000000000..e6227436fb2 --- /dev/null +++ b/adapters/nanointeractive/usersync.go @@ -0,0 +1,12 @@ +package nanointeractive + +import ( + "text/template" + + "github.com/prebid/prebid-server/adapters" + "github.com/prebid/prebid-server/usersync" +) + +func NewNanoInteractiveSyncer(temp *template.Template) usersync.Usersyncer { + return adapters.NewSyncer("nanointeractive", 72, temp, adapters.SyncTypeRedirect) +} diff --git a/adapters/nanointeractive/usersync_test.go b/adapters/nanointeractive/usersync_test.go new file mode 100644 index 00000000000..ec9787bc20d --- /dev/null +++ b/adapters/nanointeractive/usersync_test.go @@ -0,0 +1,36 @@ +package nanointeractive + +import ( + "github.com/prebid/prebid-server/privacy/ccpa" + "github.com/prebid/prebid-server/privacy/gdpr" + "testing" + "text/template" + + "github.com/prebid/prebid-server/privacy" + "github.com/stretchr/testify/assert" +) + +func TestNewNanoInteractiveSyncer(t *testing.T) { + syncURL := "https://ad.audiencemanager.de/hbs/cookie_sync?gdpr={{.GDPR}}&consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirectUri=http%3A%2F%2Flocalhost%2Fsetuid%3Fbidder%3Dnanointeractive%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24UID" + syncURLTemplate := template.Must( + template.New("sync-template").Parse(syncURL), + ) + + userSync := NewNanoInteractiveSyncer(syncURLTemplate) + syncInfo, err := userSync.GetUsersyncInfo( + privacy.Policies{ + GDPR: gdpr.Policy{ + Signal: "1", + Consent: "BONciguONcjGKADACHENAOLS1rAHDAFAAEAASABQAMwAeACEAFw", + }, + CCPA: ccpa.Policy{ + Value: "1NYN", + }, + }) + + assert.NoError(t, err) + assert.Equal(t, "https://ad.audiencemanager.de/hbs/cookie_sync?gdpr=1&consent=BONciguONcjGKADACHENAOLS1rAHDAFAAEAASABQAMwAeACEAFw&us_privacy=1NYN&redirectUri=http%3A%2F%2Flocalhost%2Fsetuid%3Fbidder%3Dnanointeractive%26gdpr%3D1%26gdpr_consent%3DBONciguONcjGKADACHENAOLS1rAHDAFAAEAASABQAMwAeACEAFw%26uid%3D%24UID", syncInfo.URL) + assert.Equal(t, "redirect", syncInfo.Type) + assert.EqualValues(t, 72, userSync.GDPRVendorID()) + assert.Equal(t, false, syncInfo.SupportCORS) +} diff --git a/config/config.go b/config/config.go index d4edab2b53f..999b1870b54 100644 --- a/config/config.go +++ b/config/config.go @@ -521,6 +521,7 @@ func (cfg *Configuration) setDerivedDefaults() { setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderLockerDome, "https://lockerdome.com/usync/prebidserver?pid="+cfg.Adapters["lockerdome"].PlatformID+"&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dlockerdome%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%7B%7Buid%7D%7D") setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderMarsmedia, "https://dmp.rtbsrv.com/dmp/profiles/cm?p_id=179&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dmarsmedia%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24%7BUUID%7D") setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderMgid, "https://cm.mgid.com/m?cdsp=363893&adu="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dmgid%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%7Bmuidn%7D") + setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderNanoInteractive, "https://ad.audiencemanager.de/hbs/cookie_sync?gdpr={{.GDPR}}&consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirectUri="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dnanointeractive%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24UID") setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderOpenx, "https://rtb.openx.net/sync/prebid?r="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dopenx%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24%7BUID%7D") setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderPubmatic, "https://ads.pubmatic.com/AdServer/js/user_sync.html?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&predirect="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dpubmatic%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D") setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderPulsepoint, "https://bh.contextweb.com/rtset?pid=561205&ev=1&rurl="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dpulsepoint%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%25%25VGUID%25%25") @@ -713,6 +714,7 @@ func SetupViper(v *viper.Viper, filename string) { v.SetDefault("adapters.lockerdome.endpoint", "https://lockerdome.com/ladbid/prebidserver/openrtb2") v.SetDefault("adapters.marsmedia.endpoint", "https://bid306.rtbsrv.com/bidder/?bid=f3xtet") v.SetDefault("adapters.mgid.endpoint", "https://prebid.mgid.com/prebid/") + v.SetDefault("adapters.nanointeractive.endpoint", "https://ad.audiencemanager.de/hbs") v.SetDefault("adapters.openx.endpoint", "http://rtb.openx.net/prebid") v.SetDefault("adapters.pubmatic.endpoint", "https://hbopenbid.pubmatic.com/translator?source=prebid-server") v.SetDefault("adapters.pubnative.endpoint", "http://dsp.pubnative.net/bid/v1/request") diff --git a/exchange/adapter_map.go b/exchange/adapter_map.go index 05f44e24b66..f7b970c571b 100644 --- a/exchange/adapter_map.go +++ b/exchange/adapter_map.go @@ -39,6 +39,7 @@ import ( "github.com/prebid/prebid-server/adapters/lockerdome" "github.com/prebid/prebid-server/adapters/marsmedia" "github.com/prebid/prebid-server/adapters/mgid" + "github.com/prebid/prebid-server/adapters/nanointeractive" "github.com/prebid/prebid-server/adapters/openx" "github.com/prebid/prebid-server/adapters/pubmatic" "github.com/prebid/prebid-server/adapters/pubnative" @@ -96,21 +97,22 @@ func newAdapterMap(client *http.Client, cfg *config.Configuration, infos adapter client, cfg.Adapters[strings.ToLower(string(openrtb_ext.BidderFacebook))].PlatformID, cfg.Adapters[strings.ToLower(string(openrtb_ext.BidderFacebook))].AppSecret), - openrtb_ext.BidderGamma: gamma.NewGammaBidder(cfg.Adapters[string(openrtb_ext.BidderGamma)].Endpoint), - openrtb_ext.BidderGamoshi: gamoshi.NewGamoshiBidder(cfg.Adapters[string(openrtb_ext.BidderGamoshi)].Endpoint), - openrtb_ext.BidderGrid: grid.NewGridBidder(cfg.Adapters[string(openrtb_ext.BidderGrid)].Endpoint), - openrtb_ext.BidderGumGum: gumgum.NewGumGumBidder(cfg.Adapters[string(openrtb_ext.BidderGumGum)].Endpoint), - openrtb_ext.BidderImprovedigital: improvedigital.NewImprovedigitalBidder(cfg.Adapters[string(openrtb_ext.BidderImprovedigital)].Endpoint), - openrtb_ext.BidderKidoz: kidoz.NewKidozBidder(cfg.Adapters[string(openrtb_ext.BidderKidoz)].Endpoint), - openrtb_ext.BidderKubient: kubient.NewKubientBidder(cfg.Adapters[string(openrtb_ext.BidderKubient)].Endpoint), - openrtb_ext.BidderLockerDome: lockerdome.NewLockerDomeBidder(cfg.Adapters[string(openrtb_ext.BidderLockerDome)].Endpoint), - openrtb_ext.BidderMarsmedia: marsmedia.NewMarsmediaBidder(cfg.Adapters[string(openrtb_ext.BidderMarsmedia)].Endpoint), - openrtb_ext.BidderMgid: mgid.NewMgidBidder(cfg.Adapters[string(openrtb_ext.BidderMgid)].Endpoint), - openrtb_ext.BidderOpenx: openx.NewOpenxBidder(cfg.Adapters[string(openrtb_ext.BidderOpenx)].Endpoint), - openrtb_ext.BidderPubmatic: pubmatic.NewPubmaticBidder(client, cfg.Adapters[string(openrtb_ext.BidderPubmatic)].Endpoint), - openrtb_ext.BidderPubnative: pubnative.NewPubnativeBidder(cfg.Adapters[string(openrtb_ext.BidderPubnative)].Endpoint), - openrtb_ext.BidderRhythmone: rhythmone.NewRhythmoneBidder(cfg.Adapters[string(openrtb_ext.BidderRhythmone)].Endpoint), - openrtb_ext.BidderRTBHouse: rtbhouse.NewRTBHouseBidder(cfg.Adapters[string(openrtb_ext.BidderRTBHouse)].Endpoint), + openrtb_ext.BidderGamma: gamma.NewGammaBidder(cfg.Adapters[string(openrtb_ext.BidderGamma)].Endpoint), + openrtb_ext.BidderGamoshi: gamoshi.NewGamoshiBidder(cfg.Adapters[string(openrtb_ext.BidderGamoshi)].Endpoint), + openrtb_ext.BidderGrid: grid.NewGridBidder(cfg.Adapters[string(openrtb_ext.BidderGrid)].Endpoint), + openrtb_ext.BidderGumGum: gumgum.NewGumGumBidder(cfg.Adapters[string(openrtb_ext.BidderGumGum)].Endpoint), + openrtb_ext.BidderImprovedigital: improvedigital.NewImprovedigitalBidder(cfg.Adapters[string(openrtb_ext.BidderImprovedigital)].Endpoint), + openrtb_ext.BidderKidoz: kidoz.NewKidozBidder(cfg.Adapters[string(openrtb_ext.BidderKidoz)].Endpoint), + openrtb_ext.BidderKubient: kubient.NewKubientBidder(cfg.Adapters[string(openrtb_ext.BidderKubient)].Endpoint), + openrtb_ext.BidderLockerDome: lockerdome.NewLockerDomeBidder(cfg.Adapters[string(openrtb_ext.BidderLockerDome)].Endpoint), + openrtb_ext.BidderMarsmedia: marsmedia.NewMarsmediaBidder(cfg.Adapters[string(openrtb_ext.BidderMarsmedia)].Endpoint), + openrtb_ext.BidderMgid: mgid.NewMgidBidder(cfg.Adapters[string(openrtb_ext.BidderMgid)].Endpoint), + openrtb_ext.BidderNanoInteractive: nanointeractive.NewNanoIneractiveBidder(cfg.Adapters[string(openrtb_ext.BidderNanoInteractive)].Endpoint), + openrtb_ext.BidderOpenx: openx.NewOpenxBidder(cfg.Adapters[string(openrtb_ext.BidderOpenx)].Endpoint), + openrtb_ext.BidderPubmatic: pubmatic.NewPubmaticBidder(client, cfg.Adapters[string(openrtb_ext.BidderPubmatic)].Endpoint), + openrtb_ext.BidderPubnative: pubnative.NewPubnativeBidder(cfg.Adapters[string(openrtb_ext.BidderPubnative)].Endpoint), + openrtb_ext.BidderRhythmone: rhythmone.NewRhythmoneBidder(cfg.Adapters[string(openrtb_ext.BidderRhythmone)].Endpoint), + openrtb_ext.BidderRTBHouse: rtbhouse.NewRTBHouseBidder(cfg.Adapters[string(openrtb_ext.BidderRTBHouse)].Endpoint), openrtb_ext.BidderRubicon: rubicon.NewRubiconBidder( client, cfg.Adapters[string(openrtb_ext.BidderRubicon)].Endpoint, diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index e3f186db333..ec9745563ef 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -57,6 +57,7 @@ const ( BidderLockerDome BidderName = "lockerdome" BidderMarsmedia BidderName = "marsmedia" BidderMgid BidderName = "mgid" + BidderNanoInteractive BidderName = "nanointeractive" BidderOpenx BidderName = "openx" BidderPubmatic BidderName = "pubmatic" BidderPubnative BidderName = "pubnative" @@ -119,6 +120,7 @@ var BidderMap = map[string]BidderName{ "lockerdome": BidderLockerDome, "marsmedia": BidderMarsmedia, "mgid": BidderMgid, + "nanointeractive": BidderNanoInteractive, "openx": BidderOpenx, "pubmatic": BidderPubmatic, "pubnative": BidderPubnative, diff --git a/openrtb_ext/imp_nanointeractive.go b/openrtb_ext/imp_nanointeractive.go new file mode 100644 index 00000000000..28db5be0d07 --- /dev/null +++ b/openrtb_ext/imp_nanointeractive.go @@ -0,0 +1,10 @@ +package openrtb_ext + +// ExtImpNanoInteractive defines the contract for bidrequest.imp[i].ext.nanointeractive +type ExtImpNanoInteractive struct { + Pid string `json:"pid"` + Nq []string `json:"nq, omitempty"` + Category string `json:"category, omitempty"` + SubId string `json:"subId, omitempty"` + Ref string `json:"ref, omitempty"` +} diff --git a/static/bidder-info/nanointeractive.yaml b/static/bidder-info/nanointeractive.yaml new file mode 100644 index 00000000000..244e7602950 --- /dev/null +++ b/static/bidder-info/nanointeractive.yaml @@ -0,0 +1,9 @@ +maintainer: + email: "development@nanointeractive.com" +capabilities: + app: + mediaTypes: + - banner + site: + mediaTypes: + - banner diff --git a/static/bidder-params/nanointeractive.json b/static/bidder-params/nanointeractive.json new file mode 100644 index 00000000000..707dff2fa50 --- /dev/null +++ b/static/bidder-params/nanointeractive.json @@ -0,0 +1,32 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "NanoInteractive Adapter Params", + "description": "A schema which validates params accepted by the NanoInteractive adapter", + "type": "object", + "properties": { + "pid": { + "type": "string", + "description": "Placement idd" + }, + "nq": { + "type": "array", + "items": { + "type": "string" + }, + "description": "search queries" + }, + "category": { + "type": "string", + "description": "IAB Category" + }, + "subId": { + "type": "string", + "description": "any segment value provided by publisher" + }, + "ref" : { + "type": "string", + "description": "referer" + } + }, + "required": ["pid"] +} \ No newline at end of file diff --git a/usersync/usersyncers/syncer.go b/usersync/usersyncers/syncer.go index c7ad70b7eff..be0392f2dbb 100644 --- a/usersync/usersyncers/syncer.go +++ b/usersync/usersyncers/syncer.go @@ -34,6 +34,7 @@ import ( "github.com/prebid/prebid-server/adapters/lockerdome" "github.com/prebid/prebid-server/adapters/marsmedia" "github.com/prebid/prebid-server/adapters/mgid" + "github.com/prebid/prebid-server/adapters/nanointeractive" "github.com/prebid/prebid-server/adapters/openx" "github.com/prebid/prebid-server/adapters/pubmatic" "github.com/prebid/prebid-server/adapters/pulsepoint" @@ -96,6 +97,7 @@ func NewSyncerMap(cfg *config.Configuration) map[openrtb_ext.BidderName]usersync insertIntoMap(cfg, syncers, openrtb_ext.BidderLockerDome, lockerdome.NewLockerDomeSyncer) insertIntoMap(cfg, syncers, openrtb_ext.BidderMarsmedia, marsmedia.NewMarsmediaSyncer) insertIntoMap(cfg, syncers, openrtb_ext.BidderMgid, mgid.NewMgidSyncer) + insertIntoMap(cfg, syncers, openrtb_ext.BidderNanoInteractive, nanointeractive.NewNanoInteractiveSyncer) insertIntoMap(cfg, syncers, openrtb_ext.BidderOpenx, openx.NewOpenxSyncer) insertIntoMap(cfg, syncers, openrtb_ext.BidderPubmatic, pubmatic.NewPubmaticSyncer) insertIntoMap(cfg, syncers, openrtb_ext.BidderPulsepoint, pulsepoint.NewPulsepointSyncer) diff --git a/usersync/usersyncers/syncer_test.go b/usersync/usersyncers/syncer_test.go index 3de64ec1eb0..383e24d82cf 100644 --- a/usersync/usersyncers/syncer_test.go +++ b/usersync/usersyncers/syncer_test.go @@ -43,6 +43,7 @@ func TestNewSyncerMap(t *testing.T) { string(openrtb_ext.BidderLockerDome): syncConfig, string(openrtb_ext.BidderMarsmedia): syncConfig, string(openrtb_ext.BidderMgid): syncConfig, + string(openrtb_ext.BidderNanoInteractive): syncConfig, string(openrtb_ext.BidderOpenx): syncConfig, string(openrtb_ext.BidderPubmatic): syncConfig, string(openrtb_ext.BidderPulsepoint): syncConfig,