diff --git a/adapters/connatix/connatix.go b/adapters/connatix/connatix.go new file mode 100644 index 00000000000..74ff5956848 --- /dev/null +++ b/adapters/connatix/connatix.go @@ -0,0 +1,236 @@ +package connatix + +import ( + "encoding/json" + "fmt" + "net/http" + "strings" + + "github.com/buger/jsonparser" + "github.com/prebid/openrtb/v20/openrtb2" + "github.com/prebid/prebid-server/v3/adapters" + "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/errortypes" + "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v3/util/jsonutil" +) + +const ( + maxImpsPerReq = 1 +) + +// Builder builds a new instance of the Connatix adapter for the given bidder with the given config. +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { + bidder := &adapter{ + endpoint: config.Endpoint, + } + return bidder, nil +} + +func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { + if request.Device == nil || (request.Device.IP == "" && request.Device.IPv6 == "") { + return nil, []error{&errortypes.BadInput{ + Message: "Device IP is required", + }} + } + + // connatix adapter expects imp.displaymanagerver to be populated in openrtb2 request + // but some SDKs will put it in imp.ext.prebid instead + displayManagerVer := buildDisplayManagerVer(request) + + var errs []error + + validImps := []openrtb2.Imp{} + + for i := range request.Imp { + impExtIncoming, err := validateAndBuildImpExt(&request.Imp[i]) + if err != nil { + errs = append(errs, err) + continue + } + + if err := buildRequestImp(&request.Imp[i], impExtIncoming, displayManagerVer, reqInfo); err != nil { + errs = append(errs, err) + continue + } + + validImps = append(validImps, request.Imp[i]) + } + + // Divide imps to several requests + requests, errors := splitRequests(validImps, request, a.endpoint) + return requests, append(errs, errors...) +} + +func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) { + if adapters.IsResponseStatusCodeNoContent(response) { + return nil, nil + } + + if err := adapters.CheckResponseStatusCodeForErrors(response); err != nil { + return nil, []error{err} + } + + var connatixResponse openrtb2.BidResponse + if err := jsonutil.Unmarshal(response.Body, &connatixResponse); err != nil { + return nil, []error{err} + } + + var errs []error + bidderResponse := adapters.NewBidderResponseWithBidsCapacity(1) + for _, sb := range connatixResponse.SeatBid { + for i := range sb.Bid { + bid := sb.Bid[i] + var bidExt bidExt + var bidType openrtb_ext.BidType + + if err := jsonutil.Unmarshal(bid.Ext, &bidExt); err != nil { + bidType = openrtb_ext.BidTypeBanner + } else { + bidType = getBidType(bidExt) + } + + bidderResponse.Bids = append(bidderResponse.Bids, &adapters.TypedBid{ + Bid: &bid, + BidType: bidType, + }) + } + } + + bidderResponse.Currency = "USD" + + return bidderResponse, errs +} + +func validateAndBuildImpExt(imp *openrtb2.Imp) (impExtIncoming, error) { + var ext impExtIncoming + if err := jsonutil.Unmarshal(imp.Ext, &ext); err != nil { + return impExtIncoming{}, err + } + + return ext, nil +} + +func splitRequests(imps []openrtb2.Imp, request *openrtb2.BidRequest, uri string) ([]*adapters.RequestData, []error) { + var errs []error + // Initial capacity for future array of requests, memory optimization. + // Let's say there are 35 impressions and limit impressions per request equals to 10. + // In this case we need to create 4 requests with 10, 10, 10 and 5 impressions. + // With this formula initial capacity=(35+10-1)/10 = 4 + initialCapacity := (len(imps) + maxImpsPerReq - 1) / maxImpsPerReq + resArr := make([]*adapters.RequestData, 0, initialCapacity) + startInd := 0 + impsLeft := len(imps) > 0 + + headers := http.Header{} + headers.Add("Content-Type", "application/json") + headers.Add("Accept", "application/json") + + if request.Device != nil { + if len(request.Device.UA) > 0 { + headers.Add("User-Agent", request.Device.UA) + } + + if len(request.Device.IPv6) > 0 { + headers.Add("X-Forwarded-For", request.Device.IPv6) + } + + if len(request.Device.IP) > 0 { + headers.Add("X-Forwarded-For", request.Device.IP) + } + } + + for impsLeft { + endInd := startInd + maxImpsPerReq + if endInd >= len(imps) { + endInd = len(imps) + impsLeft = false + } + impsForReq := imps[startInd:endInd] + request.Imp = impsForReq + + reqJSON, err := jsonutil.Marshal(request) + if err != nil { + errs = append(errs, err) + return nil, errs + } + + resArr = append(resArr, &adapters.RequestData{ + Method: "POST", + Uri: uri, + Body: reqJSON, + Headers: headers, + ImpIDs: openrtb_ext.GetImpIDs(request.Imp), + }) + startInd = endInd + } + return resArr, errs +} + +func buildRequestImp(imp *openrtb2.Imp, ext impExtIncoming, displayManagerVer string, reqInfo *adapters.ExtraRequestInfo) error { + if imp.Banner != nil { + bannerCopy := *imp.Banner + + if bannerCopy.W == nil && bannerCopy.H == nil && len(bannerCopy.Format) > 0 { + firstFormat := bannerCopy.Format[0] + bannerCopy.W = &(firstFormat.W) + bannerCopy.H = &(firstFormat.H) + } + imp.Banner = &bannerCopy + } + + // Populate imp.displaymanagerver if the SDK failed to do it. + if len(imp.DisplayManagerVer) == 0 && len(displayManagerVer) > 0 { + imp.DisplayManagerVer = displayManagerVer + } + + // Check if imp comes with bid floor amount defined in a foreign currency + if imp.BidFloor > 0 && imp.BidFloorCur != "" && !strings.EqualFold(imp.BidFloorCur, "USD") { + // Convert to US dollars + convertedValue, err := reqInfo.ConvertCurrency(imp.BidFloor, imp.BidFloorCur, "USD") + if err != nil { + return err + } + // Update after conversion. All imp elements inside request.Imp are shallow copies + // therefore, their non-pointer values are not shared memory and are safe to modify. + imp.BidFloorCur = "USD" + imp.BidFloor = convertedValue + } + + impExt := impExt{ + Connatix: impExtConnatix{ + PlacementId: ext.Bidder.PlacementId, + }, + } + + var err error + imp.Ext, err = json.Marshal(impExt) + + return err +} + +func buildDisplayManagerVer(req *openrtb2.BidRequest) string { + if req.App == nil { + return "" + } + + source, err := jsonparser.GetString(req.App.Ext, openrtb_ext.PrebidExtKey, "source") + if err != nil { + return "" + } + + version, err := jsonparser.GetString(req.App.Ext, openrtb_ext.PrebidExtKey, "version") + if err != nil { + return "" + } + + return fmt.Sprintf("%s-%s", source, version) +} + +func getBidType(ext bidExt) openrtb_ext.BidType { + if ext.Cnx.MediaType == "video" { + return openrtb_ext.BidTypeVideo + } + + return openrtb_ext.BidTypeBanner +} diff --git a/adapters/connatix/connatix_test.go b/adapters/connatix/connatix_test.go new file mode 100644 index 00000000000..018926ef25a --- /dev/null +++ b/adapters/connatix/connatix_test.go @@ -0,0 +1,20 @@ +package connatix + +import ( + "testing" + + "github.com/prebid/prebid-server/v3/adapters/adapterstest" + "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/openrtb_ext" +) + +func TestJsonSamples(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderConnatix, config.Adapter{ + Endpoint: "http://example.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, "connatixtest", bidder) +} diff --git a/adapters/connatix/connatixtest/exemplary/banner-app.json b/adapters/connatix/connatixtest/exemplary/banner-app.json new file mode 100644 index 00000000000..823c439b086 --- /dev/null +++ b/adapters/connatix/connatixtest/exemplary/banner-app.json @@ -0,0 +1,161 @@ +{ + "mockBidRequest": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "tmax": 500, + "user": { + "buyeruid": "some-user" + }, + "app": { + "publisher": { + "id": "123456789" + }, + "cat": [ + "IAB22-1" + ], + "bundle": "com.app.awesome", + "name": "Awesome App", + "domain": "awesomeapp.com", + "id": "123456789" + }, + "imp": [ + { + "id": "some-imp-id", + "tagid": "some-tag-id", + "banner": { + "format":[ + { + "w": 320, + "h": 50 + } + ] + }, + "ext": { + "bidder": { + "placementId": "some-placement-id" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://example.com", + "body": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "some-imp-id", + "tagid": "some-tag-id", + "banner": { + "w": 320, + "h": 50, + "format": [ + { + "w": 320, + "h": 50 + } + ] + }, + "ext": { + "connatix": { + "placementId": "some-placement-id" + } + } + } + ], + "app": { + "id": "123456789", + "name": "Awesome App", + "bundle": "com.app.awesome", + "domain": "awesomeapp.com", + "cat": [ + "IAB22-1" + ], + "publisher": { + "id": "123456789" + } + }, + "user": { + "buyeruid": "some-user" + }, + "tmax": 500 + }, + "impIDs": [ + "some-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-response-id", + "seatbid": [ + { + "bid": [ + { + "id": "some-bid-id", + "impid": "some-imp-id", + "price": 0.52, + "adm": "some-test-ad", + "adomain": [ + "test.com" + ], + "crid": "112233", + "w": 320, + "h": 50, + "ext": { + "connatix": { + "mediaType": "banner" + } + } + } + ], + "seat": "connatix", + "group": 0 + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "some-bid-id", + "impid": "some-imp-id", + "price": 0.52, + "adm": "some-test-ad", + "crid": "112233", + "adomain": [ + "test.com" + ], + "w": 320, + "h": 50, + "ext": { + "connatix": { + "mediaType": "banner" + } + } + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/connatix/connatixtest/exemplary/banner-web.json b/adapters/connatix/connatixtest/exemplary/banner-web.json new file mode 100644 index 00000000000..a48ef5b1be5 --- /dev/null +++ b/adapters/connatix/connatixtest/exemplary/banner-web.json @@ -0,0 +1,141 @@ +{ + "mockBidRequest": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ipv6": "test-ip-v6", + "language": "en", + "dnt": 0 + }, + "tmax": 1000, + "user": { + "buyeruid": "some-user" + }, + "site": { + "page": "test.com", + "publisher": { + "id": "123456789" + } + }, + "imp": [ + { + "id": "some-impression-id", + "tagid": "some-tag-id", + "banner": { + "w":320, + "h":50 + }, + "ext": { + "bidder": { + "placementId": "some-placement-id" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://example.com", + "headers": { + "Content-Type": ["application/json"], + "X-Forwarded-For": ["test-ip-v6"], + "Accept": ["application/json"], + "User-Agent": ["test-user-agent"] + }, + "body": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ipv6": "test-ip-v6", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "some-impression-id", + "tagid": "some-tag-id", + "banner": { + "w":320, + "h":50 + }, + "ext": { + "connatix": { + "placementId": "some-placement-id" + } + } + } + ], + "site": { + "page": "test.com", + "publisher": { + "id": "123456789" + } + }, + "user": { + "buyeruid": "some-user" + }, + "tmax": 1000 + }, + "impIDs":["some-impression-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "some-response-id", + "seatbid": [ + { + "bid": [ + { + "id": "a3ae1b4e2fc24a4fb45540082e98e161", + "impid": "some-impression-id", + "price": 0.3, + "adm": "some-test-ad", + "adomain": [ + "awesome.com" + ], + "crid": "112233", + "w": 320, + "h": 50, + "ext": { + "connatix": { + "mediaType": "banner" + } + } + } + ], + "seat": "connatix" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "bids":[ + { + "bid": { + "id": "a3ae1b4e2fc24a4fb45540082e98e161", + "impid": "some-impression-id", + "price": 0.3, + "adm": "some-test-ad", + "crid": "112233", + "adomain": [ + "awesome.com" + ], + "w": 320, + "h": 50, + "ext": { + "connatix": { + "mediaType": "banner" + } + } + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/connatix/connatixtest/exemplary/video-app.json b/adapters/connatix/connatixtest/exemplary/video-app.json new file mode 100644 index 00000000000..bff1f1b1362 --- /dev/null +++ b/adapters/connatix/connatixtest/exemplary/video-app.json @@ -0,0 +1,157 @@ +{ + "mockBidRequest": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "tmax": 1000, + "user": { + "buyeruid": "some-user" + }, + "app": { + "publisher": { + "id": "123456789" + }, + "cat": [ + "IAB22-1" + ], + "bundle": "com.app.awesome", + "name": "Awesome App", + "domain": "awesomeapp.com", + "id": "123456789" + }, + "imp": [ + { + "id": "some-impression-id", + "tagid": "some-tag-id", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480, + "minduration": 120, + "maxduration": 150 + }, + "ext": { + "bidder": { + "placementId": "some-placement-id" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://example.com", + "body": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "some-impression-id", + "video": { + "mimes": [ + "video/mp4" + ], + "minduration": 120, + "maxduration": 150, + "w": 640, + "h": 480 + }, + "tagid": "some-tag-id", + "ext": { + "connatix": { + "placementId": "some-placement-id" + } + } + } + ], + "app": { + "id": "123456789", + "name": "Awesome App", + "bundle": "com.app.awesome", + "domain": "awesomeapp.com", + "cat": [ + "IAB22-1" + ], + "publisher": { + "id": "123456789" + } + }, + "user": { + "buyeruid": "some-user" + }, + "tmax": 1000 + }, + "impIDs":["some-impression-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "some-response-id", + "seatbid": [ + { + "bid": [ + { + "id": "b3ae1b4e2fc24a4fb45540082e98e161", + "impid": "some-impression-id", + "price": 3.1, + "adm": "some-test-vast-ad", + "adomain": [ + "awesome.com" + ], + "crid": "112233", + "w": 1280, + "h": 720, + "ext": { + "connatix": { + "mediaType": "video" + } + } + } + ], + "seat": "connatix" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "bids":[ + { + "bid": { + "id": "b3ae1b4e2fc24a4fb45540082e98e161", + "impid": "some-impression-id", + "price": 3.1, + "adm": "some-test-vast-ad", + "crid": "112233", + "adomain": [ + "awesome.com" + ], + "w": 1280, + "h": 720, + "ext": { + "connatix": { + "mediaType": "video" + } + } + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/connatix/connatixtest/exemplary/video-web.json b/adapters/connatix/connatixtest/exemplary/video-web.json new file mode 100644 index 00000000000..b1ab16d0b9a --- /dev/null +++ b/adapters/connatix/connatixtest/exemplary/video-web.json @@ -0,0 +1,153 @@ +{ + "mockBidRequest": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "test-ip-v4", + "ipv6": "test-ip-v6", + "language": "en", + "dnt": 0 + }, + "tmax": 1000, + "user": { + "buyeruid": "some-user" + }, + "site": { + "page": "test.com", + "publisher": { + "id": "123456789" + } + }, + "imp": [ + { + "id": "some-impression-id", + "tagid": "some-tag-id", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480, + "minduration": 120, + "maxduration": 150 + }, + "ext": { + "bidder": { + "placementId": "some-placement-id" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://example.com", + "body": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "test-ip-v4", + "ipv6": "test-ip-v6", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "some-impression-id", + "tagid": "some-tag-id", + "video": { + "mimes": [ + "video/mp4" + ], + "minduration": 120, + "maxduration": 150, + "w": 640, + "h": 480 + }, + "ext": { + "connatix": { + "placementId": "some-placement-id" + } + } + } + ], + "site": { + "page": "test.com", + "publisher": { + "id": "123456789" + } + }, + "user": { + "buyeruid": "some-user" + }, + "tmax": 1000 + }, + "headers": { + "Content-Type": ["application/json"], + "X-Forwarded-For": ["test-ip-v6", "test-ip-v4"], + "Accept": ["application/json"], + "User-Agent": ["test-user-agent"] + }, + "impIDs":["some-impression-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "some-response-id", + "seatbid": [ + { + "bid": [ + { + "id": "b3ae1b4e2fc24a4fb45540082e98e161", + "impid": "some-impression-id", + "price": 3.5, + "adm": "some-test-vast-ad", + "adomain": [ + "awesome.com" + ], + "crid": "112233", + "w": 1280, + "h": 720, + "ext": { + "connatix": { + "mediaType": "video" + } + } + } + ], + "seat": "connatix" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "b3ae1b4e2fc24a4fb45540082e98e161", + "impid": "some-impression-id", + "price": 3.5, + "adm": "some-test-vast-ad", + "adomain": [ + "awesome.com" + ], + "crid": "112233", + "w": 1280, + "h": 720, + "ext": { + "connatix": { + "mediaType": "video" + } + } + }, + "type":"video" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/connatix/connatixtest/supplemental/bad-request-invalid-imp-ext.json b/adapters/connatix/connatixtest/supplemental/bad-request-invalid-imp-ext.json new file mode 100644 index 00000000000..3ee7a3ccbb0 --- /dev/null +++ b/adapters/connatix/connatixtest/supplemental/bad-request-invalid-imp-ext.json @@ -0,0 +1,54 @@ +{ + "mockBidRequest": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "tmax": 500, + "user": { + "buyeruid": "some-user" + }, + "app": { + "publisher": { + "id": "123456789" + }, + "cat": [ + "IAB22-1" + ], + "bundle": "com.app.awesome", + "name": "Awesome App", + "domain": "awesomeapp.com", + "id": "123456789" + }, + "imp": [ + { + "id": "some-imp-id", + "tagid": "some-tag-id", + "banner": { + "format":[ + { + "w": 320, + "h": 50 + } + ] + }, + "ext": { + "bidder": { + "placementId": {} + } + } + } + ] + }, + "httpCalls": [], + "expectedBidResponses": [], + "expectedMakeRequestsErrors": [ + { + "value": "cannot unmarshal openrtb_ext.ExtImpConnatix.PlacementId: expects \" or n, but found {", + "comparison": "literal" + } + ] + } \ No newline at end of file diff --git a/adapters/connatix/connatixtest/supplemental/bad-request-no-ip.json b/adapters/connatix/connatixtest/supplemental/bad-request-no-ip.json new file mode 100644 index 00000000000..3f7dcbf064a --- /dev/null +++ b/adapters/connatix/connatixtest/supplemental/bad-request-no-ip.json @@ -0,0 +1,46 @@ +{ + "mockBidRequest": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "language": "en", + "dnt": 0 + }, + "tmax": 1000, + "user": { + "buyeruid": "some-user" + }, + "site": { + "page": "test.com", + "publisher": { + "id": "123456789" + } + }, + "imp": [ + { + "id": "some-impression-id", + "tagid": "some-tag-id", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480, + "minduration": 120, + "maxduration": 150 + }, + "ext": { + "bidder": { + "placementId": "some-placement-id" + } + } + } + ] + }, + "expectedMakeRequestsErrors": [ + { + "value": "Device IP is required", + "comparison": "literal" + } + ] +} \ No newline at end of file diff --git a/adapters/connatix/connatixtest/supplemental/bid-response-400-status-code.json b/adapters/connatix/connatixtest/supplemental/bid-response-400-status-code.json new file mode 100644 index 00000000000..59b77c1dae5 --- /dev/null +++ b/adapters/connatix/connatixtest/supplemental/bid-response-400-status-code.json @@ -0,0 +1,113 @@ +{ + "mockBidRequest": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "tmax": 500, + "user": { + "buyeruid": "some-user" + }, + "app": { + "publisher": { + "id": "123456789" + }, + "cat": [ + "IAB22-1" + ], + "bundle": "com.app.awesome", + "name": "Awesome App", + "domain": "awesomeapp.com", + "id": "123456789" + }, + "imp": [ + { + "id": "some-imp-id", + "tagid": "some-tag-id", + "banner": { + "format":[ + { + "w": 320, + "h": 50 + } + ] + }, + "ext": { + "bidder": { + "placementId": "some-placement-id" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://example.com", + "body": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "some-imp-id", + "tagid": "some-tag-id", + "banner": { + "w": 320, + "h": 50, + "format": [ + { + "w": 320, + "h": 50 + } + ] + }, + "ext": { + "connatix": { + "placementId": "some-placement-id" + } + } + } + ], + "app": { + "id": "123456789", + "name": "Awesome App", + "bundle": "com.app.awesome", + "domain": "awesomeapp.com", + "cat": [ + "IAB22-1" + ], + "publisher": { + "id": "123456789" + } + }, + "user": { + "buyeruid": "some-user" + }, + "tmax": 500 + }, + "impIDs": [ + "some-imp-id" + ] + }, + "mockResponse": { + "status": 400, + "body": null + } + } + ], + "expectedBidResponses": [], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 400. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] + } \ No newline at end of file diff --git a/adapters/connatix/connatixtest/supplemental/bid-response-no-content.json b/adapters/connatix/connatixtest/supplemental/bid-response-no-content.json new file mode 100644 index 00000000000..6b17338d613 --- /dev/null +++ b/adapters/connatix/connatixtest/supplemental/bid-response-no-content.json @@ -0,0 +1,107 @@ +{ + "mockBidRequest": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "tmax": 500, + "user": { + "buyeruid": "some-user" + }, + "app": { + "publisher": { + "id": "123456789" + }, + "cat": [ + "IAB22-1" + ], + "bundle": "com.app.awesome", + "name": "Awesome App", + "domain": "awesomeapp.com", + "id": "123456789" + }, + "imp": [ + { + "id": "some-imp-id", + "tagid": "some-tag-id", + "banner": { + "format":[ + { + "w": 320, + "h": 50 + } + ] + }, + "ext": { + "bidder": { + "placementId": "some-placement-id" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://example.com", + "body": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "some-imp-id", + "tagid": "some-tag-id", + "banner": { + "w": 320, + "h": 50, + "format": [ + { + "w": 320, + "h": 50 + } + ] + }, + "ext": { + "connatix": { + "placementId": "some-placement-id" + } + } + } + ], + "app": { + "id": "123456789", + "name": "Awesome App", + "bundle": "com.app.awesome", + "domain": "awesomeapp.com", + "cat": [ + "IAB22-1" + ], + "publisher": { + "id": "123456789" + } + }, + "user": { + "buyeruid": "some-user" + }, + "tmax": 500 + }, + "impIDs": [ + "some-imp-id" + ] + }, + "mockResponse": { + "status": 204, + "body": null + } + } + ], + "expectedBidResponses": [] + } \ No newline at end of file diff --git a/adapters/connatix/connatixtest/supplemental/fail-build-display-manager-version.json b/adapters/connatix/connatixtest/supplemental/fail-build-display-manager-version.json new file mode 100644 index 00000000000..69ba22a6e80 --- /dev/null +++ b/adapters/connatix/connatixtest/supplemental/fail-build-display-manager-version.json @@ -0,0 +1,173 @@ +{ + "mockBidRequest": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "tmax": 500, + "user": { + "buyeruid": "some-user" + }, + "app": { + "publisher": { + "id": "123456789" + }, + "cat": [ + "IAB22-1" + ], + "bundle": "com.app.awesome", + "name": "Awesome App", + "domain": "awesomeapp.com", + "id": "123456789", + "ext": { + "prebid": { + "source": {} + } + } + }, + "imp": [ + { + "id": "some-imp-id", + "tagid": "some-tag-id", + "banner": { + "format":[ + { + "w": 320, + "h": 50 + } + ] + }, + "displaymanagerver": "1.0.0", + "ext": { + "bidder": { + "placementId": "some-placement-id" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://example.com", + "body": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "some-imp-id", + "tagid": "some-tag-id", + "banner": { + "w": 320, + "h": 50, + "format": [ + { + "w": 320, + "h": 50 + } + ] + }, + "displaymanagerver": "1.0.0", + "ext": { + "connatix": { + "placementId": "some-placement-id" + } + } + } + ], + "app": { + "id": "123456789", + "name": "Awesome App", + "bundle": "com.app.awesome", + "domain": "awesomeapp.com", + "cat": [ + "IAB22-1" + ], + "publisher": { + "id": "123456789" + }, + "ext": { + "prebid": { + "source": {} + } + } + }, + "user": { + "buyeruid": "some-user" + }, + "tmax": 500 + }, + "impIDs": [ + "some-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-response-id", + "seatbid": [ + { + "bid": [ + { + "id": "some-bid-id", + "impid": "some-imp-id", + "price": 0.52, + "adm": "some-test-ad", + "adomain": [ + "test.com" + ], + "crid": "112233", + "w": 320, + "h": 50, + "ext": { + "connatix": { + "mediaType": "banner" + } + } + } + ], + "seat": "connatix", + "group": 0 + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "some-bid-id", + "impid": "some-imp-id", + "price": 0.52, + "adm": "some-test-ad", + "crid": "112233", + "adomain": [ + "test.com" + ], + "w": 320, + "h": 50, + "ext": { + "connatix": { + "mediaType": "banner" + } + } + }, + "type": "banner" + } + ] + } + ] + } \ No newline at end of file diff --git a/adapters/connatix/connatixtest/supplemental/fail-currency-conversion.json b/adapters/connatix/connatixtest/supplemental/fail-currency-conversion.json new file mode 100644 index 00000000000..a2364eef6c5 --- /dev/null +++ b/adapters/connatix/connatixtest/supplemental/fail-currency-conversion.json @@ -0,0 +1,64 @@ +{ + "mockBidRequest": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "test-ip-v4", + "ipv6": "test-ip-v6", + "language": "en", + "dnt": 0 + }, + "tmax": 1000, + "user": { + "buyeruid": "some-user" + }, + "site": { + "page": "test.com", + "publisher": { + "id": "123456789" + } + }, + "imp": [ + { + "id": "some-impression-id", + "tagid": "some-tag-id", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480, + "minduration": 120, + "maxduration": 150 + }, + "bidfloor": 1, + "bidfloorcur": "test", + "ext": { + "bidder": { + "placementId": "some-placement-id" + } + } + } + ], + "ext": { + "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.5 + } + }, + "usepbsrates": false + } + } + } + }, + "httpCalls": [], + "expectedBidResponses": [], + "expectedMakeRequestsErrors": [ + { + "value": "currency: tag is not well-formed", + "comparison": "literal" + } + ] + } \ No newline at end of file diff --git a/adapters/connatix/connatixtest/supplemental/invalid-bid-response.json b/adapters/connatix/connatixtest/supplemental/invalid-bid-response.json new file mode 100644 index 00000000000..9fd9b448de0 --- /dev/null +++ b/adapters/connatix/connatixtest/supplemental/invalid-bid-response.json @@ -0,0 +1,116 @@ +{ + "mockBidRequest": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "tmax": 500, + "user": { + "buyeruid": "some-user" + }, + "app": { + "publisher": { + "id": "123456789" + }, + "cat": [ + "IAB22-1" + ], + "bundle": "com.app.awesome", + "name": "Awesome App", + "domain": "awesomeapp.com", + "id": "123456789" + }, + "imp": [ + { + "id": "some-imp-id", + "tagid": "some-tag-id", + "banner": { + "format":[ + { + "w": 320, + "h": 50 + } + ] + }, + "ext": { + "bidder": { + "placementId": "some-placement-id" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://example.com", + "body": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "some-imp-id", + "tagid": "some-tag-id", + "banner": { + "w": 320, + "h": 50, + "format": [ + { + "w": 320, + "h": 50 + } + ] + }, + "ext": { + "connatix": { + "placementId": "some-placement-id" + } + } + } + ], + "app": { + "id": "123456789", + "name": "Awesome App", + "bundle": "com.app.awesome", + "domain": "awesomeapp.com", + "cat": [ + "IAB22-1" + ], + "publisher": { + "id": "123456789" + } + }, + "user": { + "buyeruid": "some-user" + }, + "tmax": 500 + }, + "impIDs": [ + "some-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "some-response-id", + "seatbid": {} + } + } + } + ], + "expectedBidResponses": [], + "expectedMakeBidsErrors": [ + { + "value": "cannot unmarshal openrtb2.BidResponse.SeatBid: decode slice: expect [ or n, but found {", + "comparison": "literal" + } + ] + } \ No newline at end of file diff --git a/adapters/connatix/connatixtest/supplemental/multi-imp-request.json b/adapters/connatix/connatixtest/supplemental/multi-imp-request.json new file mode 100644 index 00000000000..08cf01fb8c6 --- /dev/null +++ b/adapters/connatix/connatixtest/supplemental/multi-imp-request.json @@ -0,0 +1,309 @@ +{ + "mockBidRequest": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "tmax": 500, + "user": { + "buyeruid": "some-user" + }, + "app": { + "publisher": { + "id": "123456789" + }, + "cat": [ + "IAB22-1" + ], + "bundle": "com.app.awesome", + "name": "Awesome App", + "domain": "awesomeapp.com", + "id": "123456789" + }, + "imp": [ + { + "id": "some-imp-id", + "tagid": "some-tag-id", + "banner": { + "format":[ + { + "w": 320, + "h": 50 + } + ] + }, + "ext": { + "bidder": { + "placementId": "some-placement-id1" + } + } + }, + { + "id": "some-impression-id", + "tagid": "some-tag-id", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480, + "minduration": 120, + "maxduration": 150 + }, + "ext": { + "bidder": { + "placementId": "some-placement-id2" + } + } + }, + { + "id": "some-invalid-impression", + "tagid": "some-tag-id", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 100, + "h": 100, + "minduration": 120, + "maxduration": 150 + }, + "ext": { + "bidder": { + "placementId": 1 + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://example.com", + "body": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "some-imp-id", + "tagid": "some-tag-id", + "banner": { + "w": 320, + "h": 50, + "format": [ + { + "w": 320, + "h": 50 + } + ] + }, + "ext": { + "connatix": { + "placementId": "some-placement-id1" + } + } + } + ], + "app": { + "id": "123456789", + "name": "Awesome App", + "bundle": "com.app.awesome", + "domain": "awesomeapp.com", + "cat": [ + "IAB22-1" + ], + "publisher": { + "id": "123456789" + } + }, + "user": { + "buyeruid": "some-user" + }, + "tmax": 500 + }, + "impIDs": [ + "some-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-response-id", + "seatbid": [ + { + "bid": [ + { + "id": "some-bid-id", + "impid": "some-imp-id", + "price": 0.52, + "adm": "some-test-ad", + "adomain": [ + "test.com" + ], + "crid": "112233", + "w": 320, + "h": 50, + "ext": { + "connatix": { + "mediaType": "banner" + } + } + } + ], + "seat": "connatix", + "group": 0 + } + ], + "cur": "USD" + } + } + }, + { + "expectedRequest": { + "uri": "http://example.com", + "body": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "some-impression-id", + "video": { + "mimes": [ + "video/mp4" + ], + "minduration": 120, + "maxduration": 150, + "w": 640, + "h": 480 + }, + "tagid": "some-tag-id", + "ext": { + "connatix": { + "placementId": "some-placement-id2" + } + } + } + ], + "app": { + "id": "123456789", + "name": "Awesome App", + "bundle": "com.app.awesome", + "domain": "awesomeapp.com", + "cat": [ + "IAB22-1" + ], + "publisher": { + "id": "123456789" + } + }, + "user": { + "buyeruid": "some-user" + }, + "tmax": 500 + }, + "impIDs":["some-impression-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "some-response-id", + "seatbid": [ + { + "bid": [ + { + "id": "b3ae1b4e2fc24a4fb45540082e98e161", + "impid": "some-impression-id", + "price": 3.1, + "adm": "some-test-vast-ad", + "adomain": [ + "awesome.com" + ], + "crid": "112233", + "w": 1280, + "h": 720, + "ext": { + "connatix": { + "mediaType": "video" + } + } + } + ], + "seat": "connatix" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "some-bid-id", + "impid": "some-imp-id", + "price": 0.52, + "adm": "some-test-ad", + "crid": "112233", + "adomain": [ + "test.com" + ], + "w": 320, + "h": 50, + "ext": { + "connatix": { + "mediaType": "banner" + } + } + }, + "type": "banner" + } + ] + }, + { + "bids":[ + { + "bid": { + "id": "b3ae1b4e2fc24a4fb45540082e98e161", + "impid": "some-impression-id", + "price": 3.1, + "adm": "some-test-vast-ad", + "crid": "112233", + "adomain": [ + "awesome.com" + ], + "w": 1280, + "h": 720, + "ext": { + "connatix": { + "mediaType": "video" + } + } + }, + "type": "video" + } + ] + } + ], + "expectedMakeRequestsErrors": [ + { + "value": "cannot unmarshal openrtb_ext.ExtImpConnatix.PlacementId: expects \" or n, but found 1", + "comparison": "literal" + } + ] + } \ No newline at end of file diff --git a/adapters/connatix/connatixtest/supplemental/non-usd-currency-converted.json b/adapters/connatix/connatixtest/supplemental/non-usd-currency-converted.json new file mode 100644 index 00000000000..9a37ce8f4ea --- /dev/null +++ b/adapters/connatix/connatixtest/supplemental/non-usd-currency-converted.json @@ -0,0 +1,181 @@ +{ + "mockBidRequest": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "test-ip-v4", + "ipv6": "test-ip-v6", + "language": "en", + "dnt": 0 + }, + "tmax": 1000, + "user": { + "buyeruid": "some-user" + }, + "site": { + "page": "test.com", + "publisher": { + "id": "123456789" + } + }, + "imp": [ + { + "id": "some-impression-id", + "tagid": "some-tag-id", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480, + "minduration": 120, + "maxduration": 150 + }, + "bidfloor": 1, + "bidfloorcur": "EUR", + "ext": { + "bidder": { + "placementId": "some-placement-id" + } + } + } + ], + "ext": { + "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.5 + } + }, + "usepbsrates": false + } + } + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://example.com", + "body": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "test-ip-v4", + "ipv6": "test-ip-v6", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "bidfloorcur": "USD", + "bidfloor": 1.5, + "id": "some-impression-id", + "tagid": "some-tag-id", + "video": { + "mimes": [ + "video/mp4" + ], + "minduration": 120, + "maxduration": 150, + "w": 640, + "h": 480 + }, + "ext": { + "connatix": { + "placementId": "some-placement-id" + } + } + } + ], + "site": { + "page": "test.com", + "publisher": { + "id": "123456789" + } + }, + "user": { + "buyeruid": "some-user" + }, + "ext": { + "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.5 + } + }, + "usepbsrates": false + } + } + }, + "tmax": 1000 + }, + "headers": { + "Content-Type": ["application/json"], + "X-Forwarded-For": ["test-ip-v6", "test-ip-v4"], + "Accept": ["application/json"], + "User-Agent": ["test-user-agent"] + }, + "impIDs":["some-impression-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "some-response-id", + "seatbid": [ + { + "bid": [ + { + "id": "b3ae1b4e2fc24a4fb45540082e98e161", + "impid": "some-impression-id", + "price": 3.5, + "adm": "some-test-vast-ad", + "adomain": [ + "awesome.com" + ], + "crid": "112233", + "w": 1280, + "h": 720, + "ext": { + "connatix": { + "mediaType": "video" + } + } + } + ], + "seat": "connatix" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "b3ae1b4e2fc24a4fb45540082e98e161", + "impid": "some-impression-id", + "price": 3.5, + "adm": "some-test-vast-ad", + "adomain": [ + "awesome.com" + ], + "crid": "112233", + "w": 1280, + "h": 720, + "ext": { + "connatix": { + "mediaType": "video" + } + } + }, + "type":"video" + } + ] + } + ] + } \ No newline at end of file diff --git a/adapters/connatix/connatixtest/supplemental/success-build-display-manager-version.json b/adapters/connatix/connatixtest/supplemental/success-build-display-manager-version.json new file mode 100644 index 00000000000..7baffa28ac7 --- /dev/null +++ b/adapters/connatix/connatixtest/supplemental/success-build-display-manager-version.json @@ -0,0 +1,174 @@ +{ + "mockBidRequest": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "tmax": 500, + "user": { + "buyeruid": "some-user" + }, + "app": { + "publisher": { + "id": "123456789" + }, + "cat": [ + "IAB22-1" + ], + "bundle": "com.app.awesome", + "name": "Awesome App", + "domain": "awesomeapp.com", + "id": "123456789", + "ext": { + "prebid": { + "source": "test", + "version": "1.0.0" + } + } + }, + "imp": [ + { + "id": "some-imp-id", + "tagid": "some-tag-id", + "banner": { + "format":[ + { + "w": 320, + "h": 50 + } + ] + }, + "ext": { + "bidder": { + "placementId": "some-placement-id" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://example.com", + "body": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "some-imp-id", + "tagid": "some-tag-id", + "banner": { + "w": 320, + "h": 50, + "format": [ + { + "w": 320, + "h": 50 + } + ] + }, + "displaymanagerver": "test-1.0.0", + "ext": { + "connatix": { + "placementId": "some-placement-id" + } + } + } + ], + "app": { + "id": "123456789", + "name": "Awesome App", + "bundle": "com.app.awesome", + "domain": "awesomeapp.com", + "cat": [ + "IAB22-1" + ], + "publisher": { + "id": "123456789" + }, + "ext": { + "prebid": { + "source": "test", + "version": "1.0.0" + } + } + }, + "user": { + "buyeruid": "some-user" + }, + "tmax": 500 + }, + "impIDs": [ + "some-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-response-id", + "seatbid": [ + { + "bid": [ + { + "id": "some-bid-id", + "impid": "some-imp-id", + "price": 0.52, + "adm": "some-test-ad", + "adomain": [ + "test.com" + ], + "crid": "112233", + "w": 320, + "h": 50, + "ext": { + "connatix": { + "mediaType": "banner" + } + } + } + ], + "seat": "connatix", + "group": 0 + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "some-bid-id", + "impid": "some-imp-id", + "price": 0.52, + "adm": "some-test-ad", + "crid": "112233", + "adomain": [ + "test.com" + ], + "w": 320, + "h": 50, + "ext": { + "connatix": { + "mediaType": "banner" + } + } + }, + "type": "banner" + } + ] + } + ] + } \ No newline at end of file diff --git a/adapters/connatix/models.go b/adapters/connatix/models.go new file mode 100644 index 00000000000..55d475f9638 --- /dev/null +++ b/adapters/connatix/models.go @@ -0,0 +1,29 @@ +package connatix + +import ( + "github.com/prebid/prebid-server/v3/openrtb_ext" +) + +type adapter struct { + endpoint string +} + +type impExtIncoming struct { + Bidder openrtb_ext.ExtImpConnatix `json:"bidder"` +} + +type impExt struct { + Connatix impExtConnatix `json:"connatix"` +} + +type impExtConnatix struct { + PlacementId string `json:"placementId,omitempty"` +} + +type bidExt struct { + Cnx bidCnxExt `json:"connatix,omitempty"` +} + +type bidCnxExt struct { + MediaType string `json:"mediaType,omitempty"` +} diff --git a/adapters/connatix/params_test.go b/adapters/connatix/params_test.go new file mode 100644 index 00000000000..254f660c1ba --- /dev/null +++ b/adapters/connatix/params_test.go @@ -0,0 +1,58 @@ +package connatix + +import ( + "encoding/json" + "testing" + + "github.com/prebid/prebid-server/v3/openrtb_ext" +) + +// This file actually intends to test static/bidder-params/connatix.json +// +// These also validate the format of the external API: request.imp[i].ext.prebid.bidder.connatix + +// TestValidParams makes sure that the Connatix 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.BidderConnatix, json.RawMessage(validParam)); err != nil { + t.Errorf("Schema rejected Connatix params: %s", validParam) + } + } +} + +// TestInvalidParams makes sure that the Connatix 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.BidderConnatix, json.RawMessage(invalidParam)); err == nil { + t.Errorf("Schema allowed unexpected params: %s", invalidParam) + } + } +} + +var validParams = []string{ + `{"placementId": "test"}`, + `{"placementId": "test1"}`, + `{"placementId": "test-1-test"}`, +} + +var invalidParams = []string{ + ``, + `null`, + `true`, + `5`, + `4.2`, + `[]`, + `{}`, + `{"adCode": "string", "seatCode": 5, "originalPublisherid": "string"}`, + `{ "placementId": "" }`, +} diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index 97a03dde2a5..e14b8868243 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -72,6 +72,7 @@ import ( "github.com/prebid/prebid-server/v3/adapters/colossus" "github.com/prebid/prebid-server/v3/adapters/compass" "github.com/prebid/prebid-server/v3/adapters/concert" + "github.com/prebid/prebid-server/v3/adapters/connatix" "github.com/prebid/prebid-server/v3/adapters/connectad" "github.com/prebid/prebid-server/v3/adapters/consumable" "github.com/prebid/prebid-server/v3/adapters/conversant" @@ -302,6 +303,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderColossus: colossus.Builder, openrtb_ext.BidderCompass: compass.Builder, openrtb_ext.BidderConcert: concert.Builder, + openrtb_ext.BidderConnatix: connatix.Builder, openrtb_ext.BidderConnectAd: connectad.Builder, openrtb_ext.BidderConsumable: consumable.Builder, openrtb_ext.BidderConversant: conversant.Builder, diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index fd7893a5a5e..5bceb3befa9 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -88,6 +88,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderColossus, BidderCompass, BidderConcert, + BidderConnatix, BidderConnectAd, BidderConsumable, BidderConversant, @@ -425,6 +426,7 @@ const ( BidderColossus BidderName = "colossus" BidderCompass BidderName = "compass" BidderConcert BidderName = "concert" + BidderConnatix BidderName = "connatix" BidderConnectAd BidderName = "connectad" BidderConsumable BidderName = "consumable" BidderConversant BidderName = "conversant" diff --git a/openrtb_ext/imp_connatix.go b/openrtb_ext/imp_connatix.go new file mode 100644 index 00000000000..18d7a713237 --- /dev/null +++ b/openrtb_ext/imp_connatix.go @@ -0,0 +1,5 @@ +package openrtb_ext + +type ExtImpConnatix struct { + PlacementId string `json:"placementId"` +} diff --git a/static/bidder-info/connatix.yaml b/static/bidder-info/connatix.yaml new file mode 100644 index 00000000000..b9b94301356 --- /dev/null +++ b/static/bidder-info/connatix.yaml @@ -0,0 +1,20 @@ +endpoint: "https://capi.connatix.com/rtb/ortb" +maintainer: + email: "pubsolutions@connatix.com" +gvlVendorID: 143 +capabilities: + app: + mediaTypes: + - banner + - video + site: + mediaTypes: + - banner + - video +userSync: + iframe: + url: "https://capi.connatix.com/us/pixel?pId=53&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&callback={{.RedirectURL}}" + userMacro: "[UID]" + redirect: + url: "https://capi.connatix.com/us/pixel?pId=52&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&callback={{.RedirectURL}}" + userMacro: "[UID]" diff --git a/static/bidder-params/connatix.json b/static/bidder-params/connatix.json new file mode 100644 index 00000000000..4003b0583b1 --- /dev/null +++ b/static/bidder-params/connatix.json @@ -0,0 +1,14 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Connatix Adapter Params", + "description": "A schema which validates params accepted by the Connatix adapter", + "type": "object", + "properties": { + "placementId": { + "type": "string", + "minLength": 1, + "description": "Placement ID" + } + }, + "required": ["placementId"] + } \ No newline at end of file