diff --git a/adapters/freewheelssp/freewheelssp.go b/adapters/freewheelssp/freewheelssp.go new file mode 100644 index 00000000000..0f82952d3e1 --- /dev/null +++ b/adapters/freewheelssp/freewheelssp.go @@ -0,0 +1,103 @@ +package freewheelssp + +import ( + "encoding/json" + "fmt" + "github.com/prebid/openrtb/v17/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" + "net/http" +) + +type adapter struct { + endpoint string +} + +func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { + for i := 0; i < len(request.Imp); i++ { + imp := &request.Imp[i] + var bidderExt adapters.ExtImpBidder + if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil { + return nil, []error{&errortypes.BadInput{ + Message: fmt.Sprintf("Invalid imp.ext for impression index %d. Error Infomation: %s", i, err.Error()), + }} + } + + var impExt openrtb_ext.ImpExtFreewheelSSP + if err := json.Unmarshal(bidderExt.Bidder, &impExt); err != nil { + return nil, []error{&errortypes.BadInput{ + Message: fmt.Sprintf("Invalid imp.ext for impression index %d. Error Infomation: %s", i, err.Error()), + }} + } + + var err error + if imp.Ext, err = json.Marshal(impExt); err != nil { + return nil, []error{&errortypes.BadInput{ + Message: fmt.Sprintf("Unable to transfer requestImpExt to Json fomat, %s", err.Error()), + }} + } + } + + requestJSON, err := json.Marshal(request) + if err != nil { + return nil, []error{&errortypes.BadInput{ + Message: fmt.Sprintf("Unable to transfer request to Json fomat, %s", err.Error()), + }} + } + + headers := http.Header{} + headers.Add("Componentid", "prebid-go") + + requestData := &adapters.RequestData{ + Method: "POST", + Uri: a.endpoint, + Body: requestJSON, + Headers: headers, + } + return []*adapters.RequestData{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.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 openrtb2.BidResponse + if err := json.Unmarshal(response.Body, &bidResp); err != nil { + return nil, []error{err} + } + + cur := bidResp.Cur + bidResponse := &adapters.BidderResponse{ + Currency: cur, + Bids: []*adapters.TypedBid{}, + } + + bidType := openrtb_ext.BidTypeVideo + + for _, seatBid := range bidResp.SeatBid { + for i := range seatBid.Bid { + b := &adapters.TypedBid{ + Bid: &seatBid.Bid[i], + BidType: bidType, + } + bidResponse.Bids = append(bidResponse.Bids, b) + } + } + return bidResponse, nil +} + +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { + bidder := &adapter{ + config.Endpoint, + } + return bidder, nil +} diff --git a/adapters/freewheelssp/freewheelssp_test.go b/adapters/freewheelssp/freewheelssp_test.go new file mode 100644 index 00000000000..5f06a29c2fd --- /dev/null +++ b/adapters/freewheelssp/freewheelssp_test.go @@ -0,0 +1,19 @@ +package freewheelssp + +import ( + "github.com/prebid/prebid-server/adapters/adapterstest" + "github.com/prebid/prebid-server/config" + "github.com/prebid/prebid-server/openrtb_ext" + "testing" +) + +func TestJsonSamples(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderFreewheelSSP, config.Adapter{ + Endpoint: "https://testjsonsample.com"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "freewheelssptest", bidder) +} diff --git a/adapters/freewheelssp/freewheelssptest/exemplary/multi-imp.json b/adapters/freewheelssp/freewheelssptest/exemplary/multi-imp.json new file mode 100644 index 00000000000..5ec36993375 --- /dev/null +++ b/adapters/freewheelssp/freewheelssptest/exemplary/multi-imp.json @@ -0,0 +1,144 @@ +{ + "mockBidRequest": { + "id": "freewheelssp-test", + "site": { + "page": "prebid.org" + }, + "imp": [ + { + "id": "imp-1", + "video": { + "mimes": ["video/mp4"], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "zoneId": 12345 + } + } + }, + { + "id": "imp-2", + "video": { + "mimes": ["video/mp4"], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "zoneId": 12346 + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://testjsonsample.com", + "body":{ + "id": "freewheelssp-test", + "site": { + "page": "prebid.org" + }, + "imp": [ + { + "id": "imp-1", + "video": { + "mimes": ["video/mp4"], + "w": 300, + "h": 250 + }, + "ext": { + "zoneId": 12345 + } + }, + { + "id": "imp-2", + "video": { + "mimes": ["video/mp4"], + "w": 300, + "h": 250 + }, + "ext": { + "zoneId": 12346 + } + } + ] + }, + "headers": { + "Componentid": [ + "prebid-go" + ] + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "freewheelssp-test", + "seatbid": [ + { + "bid": [ + { + "id": "12345_freewheelssp-test_1", + "impid": "imp-1", + "price": 1.0, + "adid": "7857", + "adm": "", + "cid": "4001", + "crid": "7857" + }, + { + "id": "12346_freewheelssp-test_2", + "impid": "imp-2", + "price": 1.0, + "adid": "7933", + "adm": "", + "cid": "3476", + "crid": "7933" + } + ], + "seat": "freewheelsspTv" + } + ], + "bidid": "freewheelssp-test", + "cur": "EUR" + } + } + } + ], + + "expectedBidResponses": [ + { + "currency": "CUR", + "bids": [ + { + "bid": { + "id": "12345_freewheelssp-test_1", + "impid": "imp-1", + "price": 1.0, + "adid": "7857", + "adm": "", + "cid": "4001", + "crid": "7857" + }, + "type": "video" + }, + { + "bid": { + "id": "12346_freewheelssp-test_2", + "impid": "imp-2", + "price": 1.0, + "adid": "7933", + "adm": "", + "cid": "3476", + "crid": "7933" + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/freewheelssp/freewheelssptest/exemplary/single-imp.json b/adapters/freewheelssp/freewheelssptest/exemplary/single-imp.json new file mode 100644 index 00000000000..1d55dfecaf0 --- /dev/null +++ b/adapters/freewheelssp/freewheelssptest/exemplary/single-imp.json @@ -0,0 +1,97 @@ +{ + "mockBidRequest": { + "id": "freewheelssp-test", + "site": { + "page": "prebid.org" + }, + "imp": [ + { + "id": "imp-1", + "video": { + "mimes": ["video/mp4"], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "zoneId": 12345 + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://testjsonsample.com", + "body":{ + "id": "freewheelssp-test", + "site": { + "page": "prebid.org" + }, + "imp": [{ + "id": "imp-1", + "video": { + "mimes": ["video/mp4"], + "w": 300, + "h": 250 + }, + "ext": { + "zoneId": 12345 + } + }] + }, + "headers": { + "Componentid": [ + "prebid-go" + ] + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "freewheelssp-test", + "seatbid": [ + { + "bid": [ + { + "id": "12345_freewheelssp-test_1", + "impid": "imp-1", + "price": 1.0, + "adid": "7857", + "adm": "", + "cid": "4001", + "crid": "7857" + } + ], + "seat": "freewheelsspTv" + } + ], + "bidid": "freewheelssp-test", + "cur": "EUR" + } + } + } + ], + + "expectedBidResponses": [ + { + "currency": "CUR", + "bids": [ + { + "bid": { + "id": "12345_freewheelssp-test_1", + "impid": "imp-1", + "price": 1.0, + "adid": "7857", + "adm": "", + "cid": "4001", + "crid": "7857" + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/freewheelssp/freewheelssptest/supplemental/204-bid-response.json b/adapters/freewheelssp/freewheelssptest/supplemental/204-bid-response.json new file mode 100644 index 00000000000..a84fa4f1268 --- /dev/null +++ b/adapters/freewheelssp/freewheelssptest/supplemental/204-bid-response.json @@ -0,0 +1,60 @@ +{ + "mockBidRequest": { + "id": "freewheelssp-test", + "site": { + "page": "prebid.org" + }, + "imp": [ + { + "id": "imp-1", + "video": { + "mimes": ["video/mp4"], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "zoneId": 12345 + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://testjsonsample.com", + "body":{ + "id": "freewheelssp-test", + "site": { + "page": "prebid.org" + }, + "imp": [{ + "id": "imp-1", + "video": { + "mimes": ["video/mp4"], + "w": 300, + "h": 250 + }, + "ext": { + "zoneId": 12345 + } + }] + }, + "headers": { + "Componentid": [ + "prebid-go" + ] + } + }, + "mockResponse": { + "status": 204, + "body" : {} + } + } + ], + + "expectedBidResponses": [] +} + diff --git a/adapters/freewheelssp/freewheelssptest/supplemental/503-bid-response.json b/adapters/freewheelssp/freewheelssptest/supplemental/503-bid-response.json new file mode 100644 index 00000000000..475114d0230 --- /dev/null +++ b/adapters/freewheelssp/freewheelssptest/supplemental/503-bid-response.json @@ -0,0 +1,64 @@ +{ + "mockBidRequest": { + "id": "freewheelssp-test", + "site": { + "page": "prebid.org" + }, + "imp": [ + { + "id": "imp-1", + "video": { + "mimes": ["video/mp4"], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "zoneId": 12345 + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://testjsonsample.com", + "body":{ + "id": "freewheelssp-test", + "site": { + "page": "prebid.org" + }, + "imp": [{ + "id": "imp-1", + "video": { + "mimes": ["video/mp4"], + "w": 300, + "h": 250 + }, + "ext": { + "zoneId": 12345 + } + }] + }, + "headers": { + "Componentid": [ + "prebid-go" + ] + } + }, + "mockResponse": { + "status": 503, + "body" : {} + } + } + ], + + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 503. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] +} \ No newline at end of file diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index 26abc217248..f4d747333e3 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -71,6 +71,7 @@ import ( "github.com/prebid/prebid-server/adapters/engagebdr" "github.com/prebid/prebid-server/adapters/eplanning" "github.com/prebid/prebid-server/adapters/epom" + "github.com/prebid/prebid-server/adapters/freewheelssp" "github.com/prebid/prebid-server/adapters/gamma" "github.com/prebid/prebid-server/adapters/gamoshi" "github.com/prebid/prebid-server/adapters/grid" @@ -230,6 +231,8 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderEPlanning: eplanning.Builder, openrtb_ext.BidderEpom: epom.Builder, openrtb_ext.BidderEVolution: evolution.Builder, + openrtb_ext.BidderFreewheelSSP: freewheelssp.Builder, + openrtb_ext.BidderFreewheelSSPOld: freewheelssp.Builder, openrtb_ext.BidderGamma: gamma.Builder, openrtb_ext.BidderGamoshi: gamoshi.Builder, openrtb_ext.BidderGrid: grid.Builder, diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index e4c68fe62b1..b4baf3d7f4b 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -151,6 +151,8 @@ const ( BidderEPlanning BidderName = "eplanning" BidderEpom BidderName = "epom" BidderEVolution BidderName = "e_volution" + BidderFreewheelSSP BidderName = "freewheelssp" + BidderFreewheelSSPOld BidderName = "freewheel-ssp" BidderGamma BidderName = "gamma" BidderGamoshi BidderName = "gamoshi" BidderGrid BidderName = "grid" @@ -318,6 +320,8 @@ func CoreBidderNames() []BidderName { BidderEPlanning, BidderEpom, BidderEVolution, + BidderFreewheelSSP, + BidderFreewheelSSPOld, BidderGamma, BidderGamoshi, BidderGrid, diff --git a/openrtb_ext/bidders_validate_test.go b/openrtb_ext/bidders_validate_test.go index 2ee3dd7d806..530f260c761 100644 --- a/openrtb_ext/bidders_validate_test.go +++ b/openrtb_ext/bidders_validate_test.go @@ -50,7 +50,7 @@ func TestBidderUniquenessGatekeeping(t *testing.T) { // - Exclude duplicates of adapters for the same bidder, as it's unlikely a publisher will use both. var bidders []string for _, bidder := range CoreBidderNames() { - if bidder != BidderTripleliftNative && bidder != BidderAdkernelAdn { + if bidder != BidderTripleliftNative && bidder != BidderAdkernelAdn && bidder != BidderFreewheelSSPOld { bidders = append(bidders, string(bidder)) } } diff --git a/openrtb_ext/imp_freewheelssp.go b/openrtb_ext/imp_freewheelssp.go new file mode 100644 index 00000000000..11c22ff8154 --- /dev/null +++ b/openrtb_ext/imp_freewheelssp.go @@ -0,0 +1,5 @@ +package openrtb_ext + +type ImpExtFreewheelSSP struct { + ZoneId int `json:"zoneId"` +} diff --git a/static/bidder-info/freewheel-ssp.yaml b/static/bidder-info/freewheel-ssp.yaml new file mode 100644 index 00000000000..f013445a820 --- /dev/null +++ b/static/bidder-info/freewheel-ssp.yaml @@ -0,0 +1,16 @@ +endpoint: "https://ads.stickyadstv.com/openrtb/dsp" +maintainer: + email: prebid-maintainer@freewheel.com +gvlVendorID: 285 +modifyingVastXmlAllowed: true +capabilities: + app: + mediaTypes: + - video + site: + mediaTypes: + - video +userSync: + iframe: + url: "https://ads.stickyadstv.com/pbs-user-sync?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&r={{.RedirectURL}}" + userMacro: "{viewerid}" diff --git a/static/bidder-info/freewheelssp.yaml b/static/bidder-info/freewheelssp.yaml new file mode 100644 index 00000000000..5cef0de13b3 --- /dev/null +++ b/static/bidder-info/freewheelssp.yaml @@ -0,0 +1,16 @@ +endpoint: "https://ads.stickyadstv.com/openrtb/dsp" +maintainer: + email: prebid-maintainer@freewheel.com +gvlVendorID: 285 +modifyingVastXmlAllowed: true +capabilities: + app: + mediaTypes: + - video + site: + mediaTypes: + - video +userSync: + iframe: + url: "https://ads.stickyadstv.com/pbs-user-sync?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&r={{.RedirectURL}}" + userMacro: "{viewerid}" \ No newline at end of file diff --git a/static/bidder-params/freewheel-ssp.json b/static/bidder-params/freewheel-ssp.json new file mode 100644 index 00000000000..103aed03198 --- /dev/null +++ b/static/bidder-params/freewheel-ssp.json @@ -0,0 +1,15 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "FreewheelSSP old Adapter Params", + "description": "A schema which validates params accepted by the FreewheelSSP adapter", + "type": "object", + + "properties": { + "zoneId": { + "type": "integer", + "description": "Zone ID" + } + }, + + "required": ["zoneId"] +} diff --git a/static/bidder-params/freewheelssp.json b/static/bidder-params/freewheelssp.json new file mode 100644 index 00000000000..6f93501a3e1 --- /dev/null +++ b/static/bidder-params/freewheelssp.json @@ -0,0 +1,15 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "FreewheelSSP Adapter Params", + "description": "A schema which validates params accepted by the FreewheelSSP adapter", + "type": "object", + + "properties": { + "zoneId": { + "type": "integer", + "description": "Zone ID" + } + }, + + "required": ["zoneId"] +} \ No newline at end of file