diff --git a/adapters/bmtm/brightmountainmedia.go b/adapters/bmtm/brightmountainmedia.go new file mode 100644 index 00000000000..ffaacd7c52c --- /dev/null +++ b/adapters/bmtm/brightmountainmedia.go @@ -0,0 +1,153 @@ +package bmtm + +import ( + "encoding/json" + "fmt" + "net/http" + "strconv" + + "github.com/mxmCherry/openrtb/v15/openrtb2" + "github.com/prebid/prebid-server/adapters" + "github.com/prebid/prebid-server/config" + "github.com/prebid/prebid-server/errortypes" + "github.com/prebid/prebid-server/openrtb_ext" +) + +type adapter struct { + endpoint string +} + +// Builder builds a new instance of the BrightMountainMedia adapter for the given bidder with the given config. +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (adapters.Bidder, error) { + bidder := &adapter{ + endpoint: config.Endpoint, + } + return bidder, nil +} + +func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { + var extRequests []*adapters.RequestData + var errs []error + + for _, imp := range request.Imp { + extRequest, err := a.makeRequest(*request, imp) + if err != nil { + errs = append(errs, err) + } else { + extRequests = append(extRequests, extRequest) + } + } + return extRequests, errs +} + +func (a *adapter) makeRequest(ortbRequest openrtb2.BidRequest, ortbImp openrtb2.Imp) (*adapters.RequestData, error) { + if ortbImp.Banner == nil && ortbImp.Video == nil { + return nil, &errortypes.BadInput{ + Message: fmt.Sprintf("For Imp ID %s Banner or Video is undefined", ortbImp.ID), + } + } + + var bidderExt adapters.ExtImpBidder + if err := json.Unmarshal(ortbImp.Ext, &bidderExt); err != nil { + return nil, &errortypes.BadInput{ + Message: fmt.Sprintf("Error unmarshalling ExtImpBidder: %s", err.Error()), + } + } + + var bmtmExt openrtb_ext.ImpExtBmtm + if err := json.Unmarshal(bidderExt.Bidder, &bmtmExt); err != nil { + return nil, &errortypes.BadInput{ + Message: fmt.Sprintf("Error unmarshalling ExtImpBmtm: %s", err.Error()), + } + } + + ortbImp.TagID = strconv.Itoa(bmtmExt.PlacementID) + ortbImp.Ext = nil + ortbRequest.Imp = []openrtb2.Imp{ortbImp} + + requestJSON, err := json.Marshal(ortbRequest) + if err != nil { + return nil, err + } + + requestData := &adapters.RequestData{ + Method: http.MethodPost, + Uri: a.endpoint, + Body: requestJSON, + Headers: setHeaders(ortbRequest), + } + return requestData, nil +} + +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{&errortypes.BadInput{ + Message: fmt.Sprintf("Unknown status code: %d.", response.StatusCode), + }} + } + + if response.StatusCode != http.StatusOK { + return nil, []error{&errortypes.BadServerResponse{ + Message: fmt.Sprintf("Unknown status code: %d.", response.StatusCode), + }} + } + + var bidResp openrtb2.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 { + bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ + Bid: &sb.Bid[i], + BidType: getMediaTypeForBid(sb.Bid[i].ImpID, internalRequest.Imp), + }) + } + } + return bidResponse, nil +} + +func setHeaders(request openrtb2.BidRequest) http.Header { + headers := http.Header{} + + headers.Add("Content-Type", "application/json;charset=utf-8") + headers.Add("Accept", "application/json") + + if request.Device != nil { + if request.Device.UA != "" { + headers.Add("User-Agent", request.Device.UA) + } + + if request.Device.IP != "" { + headers.Add("X-Forwarded-For", request.Device.IP) + } else if request.Device.IPv6 != "" { + headers.Add("X-Forwarded-For", request.Device.IPv6) + } + } + + if request.Site != nil && request.Site.Page != "" { + headers.Add("Referer", request.Site.Page) + } + return headers +} + +func getMediaTypeForBid(impID string, imps []openrtb2.Imp) openrtb_ext.BidType { + for _, imp := range imps { + if imp.ID == impID { + if imp.Banner != nil { + return openrtb_ext.BidTypeBanner + } else if imp.Video != nil { + return openrtb_ext.BidTypeVideo + } + } + } + return openrtb_ext.BidTypeBanner +} diff --git a/adapters/bmtm/brightmountainmedia_test.go b/adapters/bmtm/brightmountainmedia_test.go new file mode 100644 index 00000000000..5dbc4820503 --- /dev/null +++ b/adapters/bmtm/brightmountainmedia_test.go @@ -0,0 +1,20 @@ +package bmtm + +import ( + "testing" + + "github.com/prebid/prebid-server/adapters/adapterstest" + "github.com/prebid/prebid-server/config" + "github.com/prebid/prebid-server/openrtb_ext" +) + +func TestJsonSamples(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderBmtm, config.Adapter{ + Endpoint: "https://example.com/api/pbs"}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "brightmountainmediatest", bidder) +} diff --git a/adapters/bmtm/brightmountainmediatest/exemplary/banner.json b/adapters/bmtm/brightmountainmediatest/exemplary/banner.json new file mode 100644 index 00000000000..7d6b26b6d5f --- /dev/null +++ b/adapters/bmtm/brightmountainmediatest/exemplary/banner.json @@ -0,0 +1,103 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "page": "prebid.org" + }, + "device": { + "ua": "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.101 Safari/537.36", + "ip": "73.55.27.72" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "placement_id": 329 + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.com/api/pbs", + "body": { + "id": "test-request-id", + "site": { + "page": "prebid.org" + }, + "device": { + "ua": "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.101 Safari/537.36", + "ip": "73.55.27.72" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "tagid": "329" + } + ] + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "bmtm", + "bid": [ + { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.500000, + "adm": "some-test-ad", + "crid": "crid_10", + "h": 90, + "w": 728 + } + ] + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-ad", + "crid": "crid_10", + "w": 728, + "h": 90 + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/bmtm/brightmountainmediatest/exemplary/multi-imp.json b/adapters/bmtm/brightmountainmediatest/exemplary/multi-imp.json new file mode 100644 index 00000000000..c86a2acf034 --- /dev/null +++ b/adapters/bmtm/brightmountainmediatest/exemplary/multi-imp.json @@ -0,0 +1,198 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "page": "prebid.org" + }, + "device": { + "ua": "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.101 Safari/537.36", + "ip": "73.55.27.72" + }, + "imp": [ + { + "id": "test-imp-id1", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "placement_id": 329 + } + } + }, + { + "id": "test-imp-id2", + "video": { + "mimes": [ + "video/mp4" + ], + "protocols": [ + 2, + 3, + 5, + 6 + ], + "w": 1024, + "h": 576 + }, + "ext": { + "bidder": { + "placement_id": 329 + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.com/api/pbs", + "body": { + "id": "test-request-id", + "site": { + "page": "prebid.org" + }, + "device": { + "ua": "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.101 Safari/537.36", + "ip": "73.55.27.72" + }, + "imp": [ + { + "id": "test-imp-id1", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "tagid": "329" + } + ] + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "bmtm", + "bid": [ + { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id1", + "price": 0.500000, + "adm": "some-test-ad", + "crid": "crid_10", + "h": 90, + "w": 728 + } + ] + } + ], + "cur": "USD" + } + } + }, + { + "expectedRequest": { + "uri": "https://example.com/api/pbs", + "body": { + "id": "test-request-id", + "site": { + "page": "prebid.org" + }, + "device": { + "ua": "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.101 Safari/537.36", + "ip": "73.55.27.72" + }, + "imp": [ + { + "id": "test-imp-id2", + "video": { + "mimes": [ + "video/mp4" + ], + "protocols": [ + 2, + 3, + 5, + 6 + ], + "w": 1024, + "h": 576 + }, + "tagid": "329" + } + ] + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "bmtm", + "bid": [ + { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id2", + "price": 0.500000, + "adm": "some-test-ad", + "crid": "crid_10", + "h": 90, + "w": 728 + } + ] + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id1", + "price": 0.5, + "adm": "some-test-ad", + "crid": "crid_10", + "w": 728, + "h": 90 + }, + "type": "banner" + } + ] + }, + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id2", + "price": 0.5, + "adm": "some-test-ad", + "crid": "crid_10", + "w": 728, + "h": 90 + }, + "type": "video" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/bmtm/brightmountainmediatest/exemplary/video.json b/adapters/bmtm/brightmountainmediatest/exemplary/video.json new file mode 100644 index 00000000000..72035647eea --- /dev/null +++ b/adapters/bmtm/brightmountainmediatest/exemplary/video.json @@ -0,0 +1,113 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "page": "prebid.org" + }, + "device": { + "ua": "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.101 Safari/537.36", + "ip": "73.55.27.72" + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": [ + "video/mp4" + ], + "protocols": [ + 2, + 3, + 5, + 6 + ], + "w": 1024, + "h": 576 + }, + "ext": { + "bidder": { + "placement_id": 329 + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.com/api/pbs", + "body": { + "id": "test-request-id", + "site": { + "page": "prebid.org" + }, + "device": { + "ua": "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.101 Safari/537.36", + "ip": "73.55.27.72" + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": [ + "video/mp4" + ], + "protocols": [ + 2, + 3, + 5, + 6 + ], + "w": 1024, + "h": 576 + }, + "tagid": "329" + } + ] + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "bmtm", + "bid": [ + { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.500000, + "adm": "some-test-ad", + "crid": "crid_10", + "h": 90, + "w": 728 + } + ] + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-ad", + "crid": "crid_10", + "w": 728, + "h": 90 + }, + "type": "video" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/bmtm/brightmountainmediatest/params/race/banner.json b/adapters/bmtm/brightmountainmediatest/params/race/banner.json new file mode 100644 index 00000000000..efafd65f027 --- /dev/null +++ b/adapters/bmtm/brightmountainmediatest/params/race/banner.json @@ -0,0 +1,3 @@ +{ + "placement_id": 329 +} \ No newline at end of file diff --git a/adapters/bmtm/brightmountainmediatest/params/race/video.json b/adapters/bmtm/brightmountainmediatest/params/race/video.json new file mode 100644 index 00000000000..efafd65f027 --- /dev/null +++ b/adapters/bmtm/brightmountainmediatest/params/race/video.json @@ -0,0 +1,3 @@ +{ + "placement_id": 329 +} \ No newline at end of file diff --git a/adapters/bmtm/brightmountainmediatest/supplemental/multi-imp-mixed-validation.json b/adapters/bmtm/brightmountainmediatest/supplemental/multi-imp-mixed-validation.json new file mode 100644 index 00000000000..09659cfb5f2 --- /dev/null +++ b/adapters/bmtm/brightmountainmediatest/supplemental/multi-imp-mixed-validation.json @@ -0,0 +1,117 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "page": "prebid.org" + }, + "device": { + "ua": "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.101 Safari/537.36", + "ip": "73.55.27.72" + }, + "imp": [ + { + "id": "test-imp-id1", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "placement_id": 329 + } + } + }, + { + "id": "test-imp-id2", + "ext": { + "bidder": { + "placement_id": 329 + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.com/api/pbs", + "body": { + "id": "test-request-id", + "site": { + "page": "prebid.org" + }, + "device": { + "ua": "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.101 Safari/537.36", + "ip": "73.55.27.72" + }, + "imp": [ + { + "id": "test-imp-id1", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "tagid": "329" + } + ] + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "brightx", + "bid": [ + { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id1", + "price": 0.500000, + "adm": "some-test-ad", + "crid": "crid_10", + "h": 90, + "w": 728 + } + ] + } + ], + "cur": "USD" + } + } + } + ], + "expectedMakeRequestsErrors": [ + { + "value": "For Imp ID test-imp-id2 Banner or Video is undefined", + "comparison": "literal" + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id1", + "price": 0.5, + "adm": "some-test-ad", + "crid": "crid_10", + "w": 728, + "h": 90 + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/bmtm/brightmountainmediatest/supplemental/status-not-ok.json b/adapters/bmtm/brightmountainmediatest/supplemental/status-not-ok.json new file mode 100644 index 00000000000..12ec25e23c4 --- /dev/null +++ b/adapters/bmtm/brightmountainmediatest/supplemental/status-not-ok.json @@ -0,0 +1,80 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "page": "prebid.org" + }, + "device": { + "ua": "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.101 Safari/537.36", + "ip": "73.55.27.72" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "placement_id": 329 + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.com/api/pbs", + "body": { + "id": "test-request-id", + "site": { + "page": "prebid.org" + }, + "device": { + "ua": "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.101 Safari/537.36", + "ip": "73.55.27.72" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "tagid": "329" + } + ] + } + }, + "mockResponse": { + "status": 400, + "body": { + "error": { + "message": "Validation failed", + "details": [ + { + "message": "placement_id is invalid" + } + ] + } + } + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Unknown status code: 400.", + "comparison": "literal" + } + ] +} \ No newline at end of file diff --git a/adapters/bmtm/params_test.go b/adapters/bmtm/params_test.go new file mode 100644 index 00000000000..8b196f1eec8 --- /dev/null +++ b/adapters/bmtm/params_test.go @@ -0,0 +1,44 @@ +package bmtm + +import ( + "encoding/json" + "testing" + + "github.com/prebid/prebid-server/openrtb_ext" +) + +func TestValidParams(t *testing.T) { + validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") + if err != nil { + t.Fatalf("Failed to fetch the json schema. %v", err) + } + + for _, validParam := range validParams { + if err := validator.Validate(openrtb_ext.BidderBmtm, json.RawMessage(validParam)); err != nil { + t.Errorf("Schema rejected valid 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 schema. %v", err) + } + + for _, invalidParam := range invalidParams { + if err := validator.Validate(openrtb_ext.BidderBmtm, json.RawMessage(invalidParam)); err == nil { + t.Errorf("Schema allowed invalid params: %s", invalidParam) + } + } +} + +var validParams = []string{ + `{"placement_id": 329}`, + `{"placement_id": 12450}`, +} + +var invalidParams = []string{ + `{"placement_id": "548d4e75w7a5d8e1w7w5r7ee7"}`, + `{"placement_id": "42"}`, +} diff --git a/adapters/bmtm/usersync.go b/adapters/bmtm/usersync.go new file mode 100644 index 00000000000..e89dec3b3a7 --- /dev/null +++ b/adapters/bmtm/usersync.go @@ -0,0 +1,12 @@ +package bmtm + +import ( + "text/template" + + "github.com/prebid/prebid-server/adapters" + "github.com/prebid/prebid-server/usersync" +) + +func NewBmtmSyncer(template *template.Template) usersync.Usersyncer { + return adapters.NewSyncer("bmtm", template, adapters.SyncTypeRedirect) +} diff --git a/adapters/bmtm/usersync_test.go b/adapters/bmtm/usersync_test.go new file mode 100644 index 00000000000..e22ec822d63 --- /dev/null +++ b/adapters/bmtm/usersync_test.go @@ -0,0 +1,29 @@ +package bmtm + +import ( + "testing" + "text/template" + + "github.com/prebid/prebid-server/privacy" + "github.com/prebid/prebid-server/privacy/gdpr" + "github.com/stretchr/testify/assert" +) + +func TestSyncer(t *testing.T) { + syncURL := "https://synctest/?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&url=localhost%2Fsetuid%3Fbidder%3Dbmtm%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3DUUID" + syncURLTemplate := template.Must( + template.New("sync-template").Parse(syncURL), + ) + + syncer := NewBmtmSyncer(syncURLTemplate) + syncInfo, err := syncer.GetUsersyncInfo(privacy.Policies{ + GDPR: gdpr.Policy{ + Signal: "1", + Consent: "consent-string", + }, + }) + + assert.NoError(t, err) + assert.Equal(t, "https://synctest/?gdpr=1&gdpr_consent=consent-string&url=localhost%2Fsetuid%3Fbidder%3Dbmtm%26gdpr%3D1%26gdpr_consent%3Dconsent-string%26uid%3DUUID", syncInfo.URL) + assert.Equal(t, "redirect", syncInfo.Type) +} diff --git a/config/config.go b/config/config.go index 27e917e4333..b30657a7381 100644 --- a/config/config.go +++ b/config/config.go @@ -592,6 +592,7 @@ func (cfg *Configuration) setDerivedDefaults() { setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderBeachfront, "https://sync.bfmio.com/sync_s2s?gdpr={{.GDPR}}&us_privacy={{.USPrivacy}}&url="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dbeachfront%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%5Bio_cid%5D") setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderBeintoo, "https://ib.beintoo.com/um?ssp=pbs&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dbeintoo%26uid%3D%24UID") // openrtb_ext.BidderBidsCube doesn't have a good default. + // openrtb_ext.BidderBmtm doesn't have a good default. setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderBrightroll, "https://pr-bh.ybp.yahoo.com/sync/appnexusprebidserver/?gdpr={{.GDPR}}&euconsent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&url="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dbrightroll%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24UID") setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderColossus, "https://sync.colossusssp.com/pbs.gif?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redir="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dcolossus%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%5BUID%5D") setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderConnectAd, "https://cdn.connectad.io/connectmyusers.php?gdpr={{.GDPR}}&consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&cb="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dconnectad%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D") @@ -844,6 +845,7 @@ func SetupViper(v *viper.Viper, filename string) { v.SetDefault("adapters.between.endpoint", "http://{{.Host}}.betweendigital.com/openrtb_bid?sspId={{.PublisherID}}") v.SetDefault("adapters.bidmachine.endpoint", "https://{{.Host}}.bidmachine.io") v.SetDefault("adapters.bidscube.endpoint", "http://supply.bidscube.com/?c=o&m=rtb") + v.SetDefault("adapters.bmtm.endpoint", "https://one.elitebidder.com/api/pbs") v.SetDefault("adapters.brightroll.endpoint", "http://east-bid.ybp.yahoo.com/bid/appnexuspbs") v.SetDefault("adapters.colossus.endpoint", "http://colossusssp.com/?c=o&m=rtb") v.SetDefault("adapters.connectad.endpoint", "http://bidder.connectad.io/API?src=pbs") diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index 8cee98429d8..76cbc2197d9 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -33,6 +33,7 @@ import ( "github.com/prebid/prebid-server/adapters/between" "github.com/prebid/prebid-server/adapters/bidmachine" "github.com/prebid/prebid-server/adapters/bidscube" + "github.com/prebid/prebid-server/adapters/bmtm" "github.com/prebid/prebid-server/adapters/brightroll" "github.com/prebid/prebid-server/adapters/colossus" "github.com/prebid/prebid-server/adapters/connectad" @@ -150,6 +151,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderBetween: between.Builder, openrtb_ext.BidderBidmachine: bidmachine.Builder, openrtb_ext.BidderBidsCube: bidscube.Builder, + openrtb_ext.BidderBmtm: bmtm.Builder, openrtb_ext.BidderBrightroll: brightroll.Builder, openrtb_ext.BidderColossus: colossus.Builder, openrtb_ext.BidderConnectAd: connectad.Builder, diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index 1bc75d5f63e..26119000283 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -104,6 +104,7 @@ const ( BidderBetween BidderName = "between" BidderBidmachine BidderName = "bidmachine" BidderBidsCube BidderName = "bidscube" + BidderBmtm BidderName = "bmtm" BidderBrightroll BidderName = "brightroll" BidderColossus BidderName = "colossus" BidderConnectAd BidderName = "connectad" @@ -222,6 +223,7 @@ func CoreBidderNames() []BidderName { BidderBetween, BidderBidmachine, BidderBidsCube, + BidderBmtm, BidderBrightroll, BidderColossus, BidderConnectAd, diff --git a/openrtb_ext/imp_bmtm.go b/openrtb_ext/imp_bmtm.go new file mode 100644 index 00000000000..a9fd7a52c5e --- /dev/null +++ b/openrtb_ext/imp_bmtm.go @@ -0,0 +1,5 @@ +package openrtb_ext + +type ImpExtBmtm struct { + PlacementID int `json:"placement_id"` +} diff --git a/static/bidder-info/bmtm.yaml b/static/bidder-info/bmtm.yaml new file mode 100644 index 00000000000..c13bf17db73 --- /dev/null +++ b/static/bidder-info/bmtm.yaml @@ -0,0 +1,8 @@ +maintainer: + email: dev@brightmountainmedia.com +modifyingVastXmlAllowed: false +capabilities: + site: + mediaTypes: + - banner + - video diff --git a/static/bidder-params/bmtm.json b/static/bidder-params/bmtm.json new file mode 100644 index 00000000000..f1fbbddc7c6 --- /dev/null +++ b/static/bidder-params/bmtm.json @@ -0,0 +1,16 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Bright Mountain Media Adapter Params", + "description": "A schema which validates params accepted by the Bright Mountain Media adapter", + "type": "object", + "properties": { + "placement_id": { + "type": "number", + "minimum": 1, + "description": "Placement ID from Bright Mountain Media" + } + }, + "required": [ + "placement_id" + ] +} \ No newline at end of file diff --git a/usersync/usersyncers/syncer.go b/usersync/usersyncers/syncer.go index 6125780e09c..1c4e809e72b 100644 --- a/usersync/usersyncers/syncer.go +++ b/usersync/usersyncers/syncer.go @@ -28,6 +28,7 @@ import ( "github.com/prebid/prebid-server/adapters/beachfront" "github.com/prebid/prebid-server/adapters/beintoo" "github.com/prebid/prebid-server/adapters/between" + "github.com/prebid/prebid-server/adapters/bmtm" "github.com/prebid/prebid-server/adapters/brightroll" "github.com/prebid/prebid-server/adapters/colossus" "github.com/prebid/prebid-server/adapters/connectad" @@ -124,6 +125,7 @@ func NewSyncerMap(cfg *config.Configuration) map[openrtb_ext.BidderName]usersync insertIntoMap(cfg, syncers, openrtb_ext.BidderAvocet, avocet.NewAvocetSyncer) insertIntoMap(cfg, syncers, openrtb_ext.BidderBeachfront, beachfront.NewBeachfrontSyncer) insertIntoMap(cfg, syncers, openrtb_ext.BidderBeintoo, beintoo.NewBeintooSyncer) + insertIntoMap(cfg, syncers, openrtb_ext.BidderBmtm, bmtm.NewBmtmSyncer) insertIntoMap(cfg, syncers, openrtb_ext.BidderBrightroll, brightroll.NewBrightrollSyncer) insertIntoMap(cfg, syncers, openrtb_ext.BidderColossus, colossus.NewColossusSyncer) insertIntoMap(cfg, syncers, openrtb_ext.BidderConnectAd, connectad.NewConnectAdSyncer) diff --git a/usersync/usersyncers/syncer_test.go b/usersync/usersyncers/syncer_test.go index 07e09695beb..92eecc9562f 100644 --- a/usersync/usersyncers/syncer_test.go +++ b/usersync/usersyncers/syncer_test.go @@ -37,6 +37,7 @@ func TestNewSyncerMap(t *testing.T) { string(openrtb_ext.BidderBeachfront): syncConfig, string(openrtb_ext.BidderBeintoo): syncConfig, string(openrtb_ext.BidderBetween): syncConfig, + string(openrtb_ext.BidderBmtm): syncConfig, string(openrtb_ext.BidderBrightroll): syncConfig, string(openrtb_ext.BidderColossus): syncConfig, string(openrtb_ext.BidderConnectAd): syncConfig,