From d8347798d901dfb5a5687077550a8cf1c3adcbb0 Mon Sep 17 00:00:00 2001 From: "jack.hsieh" Date: Fri, 27 Dec 2019 14:19:51 +0800 Subject: [PATCH] add ucfunnel adapter --- adapters/ucfunnel/params_test.go | 47 ++++++ adapters/ucfunnel/ucfunnel.go | 142 ++++++++++++++++++ adapters/ucfunnel/ucfunnel_test.go | 90 +++++++++++ .../ucfunneltest/exemplary/ucfunnel.json | 103 +++++++++++++ .../ucfunneltest/params/race/banner.json | 5 + .../ucfunneltest/params/race/video.json | 5 + adapters/ucfunnel/usersync.go | 12 ++ adapters/ucfunnel/usersync_test.go | 30 ++++ config/config.go | 2 + exchange/adapter_map.go | 2 + openrtb_ext/bidders.go | 2 + openrtb_ext/imp_ucfunnel.go | 7 + static/bidder-info/ucfunnel.yaml | 11 ++ static/bidder-params/ucfunnel.json | 17 +++ usersync/usersyncers/syncer.go | 2 + usersync/usersyncers/syncer_test.go | 1 + 16 files changed, 478 insertions(+) create mode 100644 adapters/ucfunnel/params_test.go create mode 100644 adapters/ucfunnel/ucfunnel.go create mode 100644 adapters/ucfunnel/ucfunnel_test.go create mode 100644 adapters/ucfunnel/ucfunneltest/exemplary/ucfunnel.json create mode 100644 adapters/ucfunnel/ucfunneltest/params/race/banner.json create mode 100644 adapters/ucfunnel/ucfunneltest/params/race/video.json create mode 100644 adapters/ucfunnel/usersync.go create mode 100644 adapters/ucfunnel/usersync_test.go create mode 100644 openrtb_ext/imp_ucfunnel.go create mode 100644 static/bidder-info/ucfunnel.yaml create mode 100644 static/bidder-params/ucfunnel.json diff --git a/adapters/ucfunnel/params_test.go b/adapters/ucfunnel/params_test.go new file mode 100644 index 00000000000..7be1e26e4ce --- /dev/null +++ b/adapters/ucfunnel/params_test.go @@ -0,0 +1,47 @@ +package ucfunnel + +import ( + "encoding/json" + "github.com/prebid/prebid-server/openrtb_ext" + "testing" +) + +// This file actually intends to test static/bidder-params/ucfunnel.json +// +// These also validate the format of the external API: request.imp[i].ext.ucfunnel + +// TestValidParams makes sure that the ucfunnel 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.BidderUcfunnel, json.RawMessage(validParam)); err != nil { + t.Errorf("Schema rejected ucfunnel params: %s", validParam) + } + } +} + +// TestInvalidParams makes sure that the ucfunnel 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.BidderUcfunnel, json.RawMessage(invalidParam)); err == nil { + t.Errorf("Schema allowed unexpected params: %s", invalidParam) + } + } +} + +var validParams = []string{ + `{"adunitid": "ad-83444226E44368D1E32E49EEBE6D29","partnerid": "par-2EDDB423AA24474188B843EE4842932"}`, +} + +var invalidParams = []string{ + `{"unit": "123"}`, +} diff --git a/adapters/ucfunnel/ucfunnel.go b/adapters/ucfunnel/ucfunnel.go new file mode 100644 index 00000000000..9c7cd4845d4 --- /dev/null +++ b/adapters/ucfunnel/ucfunnel.go @@ -0,0 +1,142 @@ +package ucfunnel + +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 UcfunnelAdapter struct { + http *adapters.HTTPAdapter + URI string +} + +func NewUcfunnelAdapter(config *adapters.HTTPAdapterConfig, endpoint string) *UcfunnelAdapter { + return NewUcfunnelBidder(adapters.NewHTTPAdapter(config).Client, endpoint) +} + +func NewUcfunnelBidder(client *http.Client, endpoint string) *UcfunnelAdapter { + clientAdapter := &adapters.HTTPAdapter{Client: client} + return &UcfunnelAdapter{ + http: clientAdapter, + URI: endpoint, + } +} + +func (a *UcfunnelAdapter) Name() string { + return "ucfunnel" +} + +func (a *UcfunnelAdapter) SkipNoCookies() bool { + return false +} + +func (a *UcfunnelAdapter) 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 errs []error + var bidResp openrtb.BidResponse + if err := json.Unmarshal(response.Body, &bidResp); err != nil { + return nil, []error{err} + } + + var bidReq openrtb.BidRequest + if err := json.Unmarshal(externalRequest.Body, &bidReq); err != nil { + return nil, []error{err} + } + + bidResponse := adapters.NewBidderResponseWithBidsCapacity(5) + for _, sb := range bidResp.SeatBid { + for i := range sb.Bid { + bidType := getBidType(bidReq, sb.Bid[i].ImpID) + b := &adapters.TypedBid{ + Bid: &sb.Bid[i], + BidType: bidType, + } + bidResponse.Bids = append(bidResponse.Bids, b) + } + } + return bidResponse, errs +} + +func (a *UcfunnelAdapter) MakeRequests(request *openrtb.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { + errs := make([]error, 0, len(request.Imp)) + + // If all the requests were malformed, don't bother making a server call with no impressions. + if len(request.Imp) == 0 { + return nil, errs + } + + partnerId := getPartnerId(request) + if len(partnerId) == 0 { + return nil, []error{} + } + + reqJSON, err := json.Marshal(request) + if err != nil { + errs = append(errs, err) + return nil, errs + } + + headers := http.Header{} + headers.Add("Content-Type", "application/json") + + uri := a.URI + partnerId + "/request" + return []*adapters.RequestData{{ + Method: "POST", + Uri: uri, + Body: reqJSON, + Headers: headers, + }}, errs +} + +func getPartnerId(request *openrtb.BidRequest) string { + var ext ExtBidderUcfunnel + err := json.Unmarshal(request.Imp[0].Ext, &ext) + if err != nil { + return "" + } + return ext.Bidder.PartnerId +} + +func AddHeadersToRequest() http.Header { + headers := http.Header{} + headers.Add("Content-Type", "application/json;charset=utf-8") + headers.Add("Accept", "application/json") + return headers +} + +func getBidType(bidReq openrtb.BidRequest, impid string) openrtb_ext.BidType { + for i := range bidReq.Imp { + if bidReq.Imp[i].ID == impid { + if bidReq.Imp[i].Banner != nil { + return openrtb_ext.BidTypeBanner + } else if bidReq.Imp[i].Video != nil { + return openrtb_ext.BidTypeVideo + } + } + } + return openrtb_ext.BidTypeBanner +} + +type ExtBidderUcfunnel struct { + Bidder openrtb_ext.ExtImpUcfunnel `json:"bidder"` +} diff --git a/adapters/ucfunnel/ucfunnel_test.go b/adapters/ucfunnel/ucfunnel_test.go new file mode 100644 index 00000000000..f4e8b1befab --- /dev/null +++ b/adapters/ucfunnel/ucfunnel_test.go @@ -0,0 +1,90 @@ +package ucfunnel + +import ( + "encoding/json" + "testing" + + "github.com/mxmCherry/openrtb" + "github.com/prebid/prebid-server/adapters" + "github.com/prebid/prebid-server/adapters/adapterstest" +) + +func TestJsonSamples(t *testing.T) { + adapterstest.RunJSONBidderTest(t, "ucfunneltest", NewUcfunnelBidder(nil, "http://127.0.0.1:8081/tmp12.json")) +} + +func TestAddHeadersToRequest(t *testing.T) { + header := AddHeadersToRequest() + + if header == nil { + t.Errorf("actual = %v expected != %v", nil, nil) + } + + if header.Get("Content-Type") != "application/json;charset=utf-8" { + t.Errorf("actual = %s expected != %v", header.Get("Content-Type"), nil) + } + + if header.Get("Accept") != "application/json" { + t.Errorf("actual = %s expected != %v", header.Get("Accept"), nil) + } +} + +func TestUcfunnelAdapterNames(t *testing.T) { + adapter := NewUcfunnelAdapter(adapters.DefaultHTTPAdapterConfig, "http://localhost/bid") + adapterstest.VerifyStringValue(adapter.Name(), "ucfunnel", t) +} + +func TestSkipNoCookies(t *testing.T) { + adapter := NewUcfunnelAdapter(adapters.DefaultHTTPAdapterConfig, "http://localhost/bid") + status := adapter.SkipNoCookies() + if status != false { + t.Errorf("actual = %t expected != %t", status, false) + } +} + +func TestMakeRequests(t *testing.T) { + + imp := openrtb.Imp{ + ID: "1234", + Banner: &openrtb.Banner{}, + } + imp2 := openrtb.Imp{ + ID: "1235", + Video: &openrtb.Video{}, + } + + internalRequest := openrtb.BidRequest{Imp: []openrtb.Imp{imp, imp2}} + adapter := NewUcfunnelAdapter(adapters.DefaultHTTPAdapterConfig, "http://localhost/bid") + RequestData, err := adapter.MakeRequests(&internalRequest, nil) + + internalRequest.Imp[0].Ext = []byte(`{"bidder": {"adunitid": "ad-488663D474E44841E8A293379892348","partnerid": "par-7E6D2DB9A8922AB07B44A444D2BA67"}}`) + internalRequest.Imp[1].Ext = []byte(`{"bidder": {"adunitid": "ad-488663D474E44841E8A293379892348","partnerid": "par-7E6D2DB9A8922AB07B44A444D2BA67"}}`) + + adapter = NewUcfunnelAdapter(adapters.DefaultHTTPAdapterConfig, "http://localhost/bid") + RequestData, err = adapter.MakeRequests(&internalRequest, nil) + adapterstest.VerifyStringValue(RequestData[0].Method, "POST", t) + adapterstest.VerifyStringValue(RequestData[0].Uri, adapter.URI+"par-7E6D2DB9A8922AB07B44A444D2BA67/request", t) + + mockResponse200 := adapters.ResponseData{StatusCode: 200, Body: json.RawMessage(`{"seatbid":[{"bid":[{"impid":"1234"}]},{"bid":[{"impid":"1235"}]}]}`)} + mockResponse203 := adapters.ResponseData{StatusCode: 203, Body: json.RawMessage(`{"seatbid":[{"bid":[{"impid":"1234"}]},{"bid":[{"impid":"1235"}]}]}`)} + mockResponse204 := adapters.ResponseData{StatusCode: 204, Body: json.RawMessage(`{"seatbid":[{"bid":[{"impid":"1234"}]},{"bid":[{"impid":"1235"}]}]}`)} + mockResponse400 := adapters.ResponseData{StatusCode: 400, Body: json.RawMessage(`{"seatbid":[{"bid":[{"impid":"1234"}]},{"bid":[{"impid":"1235"}]}]}`)} + + BidderResponse200, err := adapter.MakeBids(&internalRequest, RequestData[0], &mockResponse200) + if BidderResponse200 != nil && err != nil { + t.Errorf("actual = %t expected == %v", err, nil) + } + BidderResponse203, err := adapter.MakeBids(&internalRequest, RequestData[0], &mockResponse203) + if BidderResponse203 == nil && err == nil { + t.Errorf("actual = %t expected != %v", err, nil) + } + BidderResponse204, err := adapter.MakeBids(&internalRequest, RequestData[0], &mockResponse204) + if BidderResponse204 == nil && err != nil { + t.Errorf("actual = %t expected != %v", err, nil) + } + BidderResponse400, err := adapter.MakeBids(&internalRequest, RequestData[0], &mockResponse400) + if BidderResponse400 == nil && err == nil { + t.Errorf("actual = %t expected != %v", err, nil) + } + +} diff --git a/adapters/ucfunnel/ucfunneltest/exemplary/ucfunnel.json b/adapters/ucfunnel/ucfunneltest/exemplary/ucfunnel.json new file mode 100644 index 00000000000..2a7e4b2b861 --- /dev/null +++ b/adapters/ucfunnel/ucfunneltest/exemplary/ucfunnel.json @@ -0,0 +1,103 @@ +{ + "imp": [ + { + "id": "1", + "banner": { + "w": 970, + "h": 250, + "mimes": [ + "image/gif", + "image/jpeg", + "image/png", + "text/html", + "text/javascript", + "application/javascript" + ], + "pos": 1, + "battr": [ + 6, + 7 + ], + "topframe": 1 + }, + "instl": 0, + "displaymanager": "aralego.com", + "displaymanagerver": "v1.0.0", + "secure": 0, + "bidfloor": 0.01, + "bidfloorcur": "USD", + "exp": 3600, + "ext":{ + "ucfunnel":{ + "adunitid":"ad-BE7E9EB323E9996218A733887B6E924" + } + } + } + ], + "id": "c901f218-4ca6-480b-97dc-c6fd50e24544", + "at": 2, + "tmax": 300, + "bcat": [ + "IAB11-1" + ], + "badv": [ + "abc.com", + "cbn.com", + "xyz.com" + ], + "regs": { + "coppa": 0, + "ext": { + "gdpr": 0 + }, + "us_privacy": "1--" + }, + "site": { + "id": "5b88fd05beffd764bb0f7a3a", + "name": "test", + "page": "http://127.0.0.1:8000/tmp66.html", + "domain": "127.0.0.1", + "cat": [ + "IAB1" + ], + "publisher": { + "id": "par-7E6D2DB9A8922AB07B44A444D2BA67" + } + }, + "device": { + "w": 1440, + "h": 900, + "dnt": 1, + "ip": "127.0.0.1", + "js": 1, + "os": "MacOS", + "osv": "10.15.1", + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.97 Safari/537.36", + "language": "zh-TW", + "devicetype": 2, + "geo": { + "country": "unknown", + "type": 2 + } + }, + "user": { + "id": "e7bf9b85-9554-441c-964e-c8112d35d17b" + }, + "source": { + "fd": 1, + "ext": { + "schain": { + "complete": 1, + "ver": "1.0", + "nodes": [ + { + "asi": "aralego.com", + "sid": "par-7E6D2DB9A8922AB07B44A444D2BA67", + "rid": "c8f800c2-d285-4cb9-8fc9-f95df52f6e0c", + "hp": 1 + } + ] + } + } + } +} \ No newline at end of file diff --git a/adapters/ucfunnel/ucfunneltest/params/race/banner.json b/adapters/ucfunnel/ucfunneltest/params/race/banner.json new file mode 100644 index 00000000000..2c8c2e1e198 --- /dev/null +++ b/adapters/ucfunnel/ucfunneltest/params/race/banner.json @@ -0,0 +1,5 @@ +{ + "adunitid": "ad-83444226E44368D1E32E49EEBE6D29", + "partnerid": "par-2EDDB423AA24474188B843EE4842932" +} + \ No newline at end of file diff --git a/adapters/ucfunnel/ucfunneltest/params/race/video.json b/adapters/ucfunnel/ucfunneltest/params/race/video.json new file mode 100644 index 00000000000..0a562b34aa1 --- /dev/null +++ b/adapters/ucfunnel/ucfunneltest/params/race/video.json @@ -0,0 +1,5 @@ +{ + "adunitid": "ad-E2B22B678D6A664E092824848D26BB2", + "partnerid": "par-2EDDB423AA24474188B843EE4842932" +} + \ No newline at end of file diff --git a/adapters/ucfunnel/usersync.go b/adapters/ucfunnel/usersync.go new file mode 100644 index 00000000000..92eba0d73e0 --- /dev/null +++ b/adapters/ucfunnel/usersync.go @@ -0,0 +1,12 @@ +package ucfunnel + +import ( + "text/template" + + "github.com/prebid/prebid-server/adapters" + "github.com/prebid/prebid-server/usersync" +) + +func NewUcfunnelSyncer(temp *template.Template) usersync.Usersyncer { + return adapters.NewSyncer("ucfunnel", 607, temp, adapters.SyncTypeRedirect) +} diff --git a/adapters/ucfunnel/usersync_test.go b/adapters/ucfunnel/usersync_test.go new file mode 100644 index 00000000000..45320b8cac1 --- /dev/null +++ b/adapters/ucfunnel/usersync_test.go @@ -0,0 +1,30 @@ +package ucfunnel + +import ( + "testing" + "text/template" + + "github.com/prebid/prebid-server/privacy" + "github.com/prebid/prebid-server/privacy/gdpr" + "github.com/stretchr/testify/assert" +) + +func TestUcfunnelSyncer(t *testing.T) { + syncURL := "//sync.aralego.com/idsync?gdpr={{.GDPR}}&redirect=externalURL.com%2Fsetuid%3Fbidder%3Ducfunnel%26uid%3DSspCookieUserId" + syncURLTemplate := template.Must( + template.New("sync-template").Parse(syncURL), + ) + + syncer := NewUcfunnelSyncer(syncURLTemplate) + syncInfo, err := syncer.GetUsersyncInfo(privacy.Policies{ + GDPR: gdpr.Policy{ + Signal: "0", + }, + }) + + assert.NoError(t, err) + assert.Equal(t, "//sync.aralego.com/idsync?gdpr=0&redirect=externalURL.com%2Fsetuid%3Fbidder%3Ducfunnel%26uid%3DSspCookieUserId", syncInfo.URL) + assert.Equal(t, "redirect", syncInfo.Type) + assert.EqualValues(t, 607, syncer.GDPRVendorID()) + assert.Equal(t, false, syncInfo.SupportCORS) +} diff --git a/config/config.go b/config/config.go index 1c7ef66eaa7..f7ba40eda01 100644 --- a/config/config.go +++ b/config/config.go @@ -525,6 +525,7 @@ func (cfg *Configuration) setDerivedDefaults() { // openrtb_ext.BidderTappx doesn't have a good default. setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderTriplelift, "https://eb2.3lift.com/getuid?gpdr={{.GDPR}}&cmp_cs={{.GDPRConsent}}&redir="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dtriplelift%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24UID") setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderTripleliftNative, "https://eb2.3lift.com/sync?gpdr={{.GDPR}}&cmp_cs={{.GDPRConsent}}") + setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderUcfunnel, "https://sync.aralego.com/idsync?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&usprivacy={{.USPrivacy}}&redirect="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Ducfunnel%26uid%3DSspCookieUserId") setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderUnruly, "https://usermatch.targeting.unrulymedia.com/pbsync?gdpr={{.GDPR}}&consent={{.GDPRConsent}}&rurl="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dunruly%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24UID") setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderVisx, "https://t.visx.net/s2s_sync?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&redir="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dvisx%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24%7BUUID%7D") // openrtb_ext.BidderVrtcal doesn't have a good default. @@ -707,6 +708,7 @@ func SetupViper(v *viper.Viper, filename string) { v.SetDefault("adapters.triplelift_native.disabled", true) v.SetDefault("adapters.triplelift_native.extra_info", "{\"publisher_whitelist\":[]}") v.SetDefault("adapters.triplelift.endpoint", "https://tlx.3lift.com/s2s/auction?supplier_id=20") + v.SetDefault("adapters.ucfunnel.endpoint", "http://apac-hk-adx.aralego.com/prebid/") v.SetDefault("adapters.unruly.endpoint", "http://targeting.unrulymedia.com/openrtb/2.2") v.SetDefault("adapters.verizonmedia.disabled", true) v.SetDefault("adapters.visx.endpoint", "https://t.visx.net/s2s_bid?wrapperType=s2s_prebid_standard") diff --git a/exchange/adapter_map.go b/exchange/adapter_map.go index d5e205378f1..87931b32d14 100644 --- a/exchange/adapter_map.go +++ b/exchange/adapter_map.go @@ -50,6 +50,7 @@ import ( "github.com/prebid/prebid-server/adapters/tappx" "github.com/prebid/prebid-server/adapters/triplelift" "github.com/prebid/prebid-server/adapters/triplelift_native" + "github.com/prebid/prebid-server/adapters/ucfunnel" "github.com/prebid/prebid-server/adapters/unruly" "github.com/prebid/prebid-server/adapters/verizonmedia" "github.com/prebid/prebid-server/adapters/visx" @@ -113,6 +114,7 @@ func newAdapterMap(client *http.Client, cfg *config.Configuration, infos adapter openrtb_ext.BidderTappx: tappx.NewTappxBidder(client, cfg.Adapters[strings.ToLower(string(openrtb_ext.BidderTappx))].Endpoint), openrtb_ext.BidderTriplelift: triplelift.NewTripleliftBidder(client, cfg.Adapters[string(openrtb_ext.BidderTriplelift)].Endpoint), openrtb_ext.BidderTripleliftNative: triplelift_native.NewTripleliftNativeBidder(client, cfg.Adapters[string(openrtb_ext.BidderTripleliftNative)].Endpoint, cfg.Adapters[string(openrtb_ext.BidderTripleliftNative)].ExtraAdapterInfo), + openrtb_ext.BidderUcfunnel: ucfunnel.NewUcfunnelBidder(client, cfg.Adapters[string(openrtb_ext.BidderUcfunnel)].Endpoint), openrtb_ext.BidderUnruly: unruly.NewUnrulyBidder(client, cfg.Adapters[string(openrtb_ext.BidderUnruly)].Endpoint), openrtb_ext.BidderVerizonMedia: verizonmedia.NewVerizonMediaBidder(client, cfg.Adapters[string(openrtb_ext.BidderVerizonMedia)].Endpoint), openrtb_ext.BidderVisx: visx.NewVisxBidder(cfg.Adapters[string(openrtb_ext.BidderVisx)].Endpoint), diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index 386eb93d2f0..80ee84706eb 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -63,6 +63,7 @@ const ( BidderTappx BidderName = "tappx" BidderTriplelift BidderName = "triplelift" BidderTripleliftNative BidderName = "triplelift_native" + BidderUcfunnel BidderName = "ucfunnel" BidderUnruly BidderName = "unruly" BidderVerizonMedia BidderName = "verizonmedia" BidderVisx BidderName = "visx" @@ -115,6 +116,7 @@ var BidderMap = map[string]BidderName{ "tappx": BidderTappx, "triplelift": BidderTriplelift, "triplelift_native": BidderTripleliftNative, + "ucfunnel": BidderUcfunnel, "unruly": BidderUnruly, "verizonmedia": BidderVerizonMedia, "visx": BidderVisx, diff --git a/openrtb_ext/imp_ucfunnel.go b/openrtb_ext/imp_ucfunnel.go new file mode 100644 index 00000000000..408c1e0a35e --- /dev/null +++ b/openrtb_ext/imp_ucfunnel.go @@ -0,0 +1,7 @@ +package openrtb_ext + +// ExtImpUcfunnel defines the contract for bidrequest.imp[i].ext.ucfunnel +type ExtImpUcfunnel struct { + AdUnitId string `json:"adunitid"` + PartnerId string `json:"partnerid"` +} diff --git a/static/bidder-info/ucfunnel.yaml b/static/bidder-info/ucfunnel.yaml new file mode 100644 index 00000000000..288b0b3f1b8 --- /dev/null +++ b/static/bidder-info/ucfunnel.yaml @@ -0,0 +1,11 @@ +maintainer: + email: "support@ucfunnel.com" +capabilities: + app: + mediaTypes: + - banner + - video + site: + mediaTypes: + - banner + - video diff --git a/static/bidder-params/ucfunnel.json b/static/bidder-params/ucfunnel.json new file mode 100644 index 00000000000..32acc4002f6 --- /dev/null +++ b/static/bidder-params/ucfunnel.json @@ -0,0 +1,17 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Ucfunnel Adapter Params", + "description": "A schema which validates params accepted by the Ucfunnel adapter", + "type": "object", + "properties": { + "adunitid": { + "type": "string", + "description": "ID for ad unit" + }, + "partnerid": { + "type": "string", + "description": "ID for partner" + } + }, + "required": ["adunitid"] +} diff --git a/usersync/usersyncers/syncer.go b/usersync/usersyncers/syncer.go index 6277993238a..c459ff1d510 100644 --- a/usersync/usersyncers/syncer.go +++ b/usersync/usersyncers/syncer.go @@ -46,6 +46,7 @@ import ( "github.com/prebid/prebid-server/adapters/synacormedia" "github.com/prebid/prebid-server/adapters/triplelift" "github.com/prebid/prebid-server/adapters/triplelift_native" + "github.com/prebid/prebid-server/adapters/ucfunnel" "github.com/prebid/prebid-server/adapters/unruly" "github.com/prebid/prebid-server/adapters/verizonmedia" "github.com/prebid/prebid-server/adapters/visx" @@ -102,6 +103,7 @@ func NewSyncerMap(cfg *config.Configuration) map[openrtb_ext.BidderName]usersync insertIntoMap(cfg, syncers, openrtb_ext.BidderSynacormedia, synacormedia.NewSynacorMediaSyncer) insertIntoMap(cfg, syncers, openrtb_ext.BidderTriplelift, triplelift.NewTripleliftSyncer) insertIntoMap(cfg, syncers, openrtb_ext.BidderTripleliftNative, triplelift_native.NewTripleliftSyncer) + insertIntoMap(cfg, syncers, openrtb_ext.BidderUcfunnel, ucfunnel.NewUcfunnelSyncer) insertIntoMap(cfg, syncers, openrtb_ext.BidderUnruly, unruly.NewUnrulySyncer) insertIntoMap(cfg, syncers, openrtb_ext.BidderVerizonMedia, verizonmedia.NewVerizonMediaSyncer) insertIntoMap(cfg, syncers, openrtb_ext.BidderVisx, visx.NewVisxSyncer) diff --git a/usersync/usersyncers/syncer_test.go b/usersync/usersyncers/syncer_test.go index 7917f81cc40..b120711fb78 100644 --- a/usersync/usersyncers/syncer_test.go +++ b/usersync/usersyncers/syncer_test.go @@ -54,6 +54,7 @@ func TestNewSyncerMap(t *testing.T) { string(openrtb_ext.BidderSynacormedia): syncConfig, string(openrtb_ext.BidderTriplelift): syncConfig, string(openrtb_ext.BidderTripleliftNative): syncConfig, + string(openrtb_ext.BidderUcfunnel): syncConfig, string(openrtb_ext.BidderUnruly): syncConfig, string(openrtb_ext.BidderVerizonMedia): syncConfig, string(openrtb_ext.BidderVisx): syncConfig,