diff --git a/adapters/intertech/intertech.go b/adapters/intertech/intertech.go new file mode 100644 index 00000000000..ae491995a76 --- /dev/null +++ b/adapters/intertech/intertech.go @@ -0,0 +1,226 @@ +package intertech + +import ( + "fmt" + "net/http" + "net/url" + "strconv" + "strings" + + "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 ( + pageIDMacro = "{{page_id}}" + impIDMacro = "{{imp_id}}" +) + +type adapter struct { + endpoint string +} + +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) { + var errs []error + var requests []*adapters.RequestData + + referer := getReferer(request) + cur := getCur(request) + + for _, imp := range request.Imp { + extImp, err := parseAndValidateImpExt(imp) + if err != nil { + errs = append(errs, err) + continue + } + + modifiedImp, err := modifyImp(imp) + if err != nil { + errs = append(errs, err) + continue + } + + modifiedUrl := a.modifyUrl(extImp, referer, cur) + + modRequest := *request + modRequest.Imp = []openrtb2.Imp{modifiedImp} + + reqData, err := buildRequestData(modRequest, modifiedUrl) + if err != nil { + errs = append(errs, err) + continue + } + + requests = append(requests, reqData) + } + + return requests, errs +} + +func parseAndValidateImpExt(imp openrtb2.Imp) (openrtb_ext.ExtImpIntertech, error) { + var bidderExt adapters.ExtImpBidder + if err := jsonutil.Unmarshal(imp.Ext, &bidderExt); err != nil { + return openrtb_ext.ExtImpIntertech{}, &errortypes.BadInput{ + Message: fmt.Sprintf("imp #%s: unable to parse bidder ext: %s", imp.ID, err), + } + } + + var extImp openrtb_ext.ExtImpIntertech + if err := jsonutil.Unmarshal(bidderExt.Bidder, &extImp); err != nil { + return openrtb_ext.ExtImpIntertech{}, &errortypes.BadInput{ + Message: fmt.Sprintf("imp #%s: unable to parse intertech ext: %s", imp.ID, err), + } + } + + return extImp, nil +} + +func modifyImp(imp openrtb2.Imp) (openrtb2.Imp, error) { + if imp.Banner != nil { + banner, err := updateBanner(imp.Banner) + if err != nil { + return openrtb2.Imp{}, &errortypes.BadInput{ + Message: fmt.Sprintf("imp #%s: %s", imp.ID, err.Error()), + } + } + imp.Banner = banner + } + return imp, nil +} + +func updateBanner(banner *openrtb2.Banner) (*openrtb2.Banner, error) { + bannerCopy := *banner + if bannerCopy.W == nil || bannerCopy.H == nil || *bannerCopy.W == 0 || *bannerCopy.H == 0 { + if len(bannerCopy.Format) > 0 { + w := bannerCopy.Format[0].W + h := bannerCopy.Format[0].H + bannerCopy.W = &w + bannerCopy.H = &h + } else { + return nil, fmt.Errorf("Invalid sizes provided for Banner") + } + } + return &bannerCopy, nil +} + +func (a *adapter) modifyUrl(extImp openrtb_ext.ExtImpIntertech, referer, cur string) string { + pageStr := strconv.Itoa(extImp.PageID) + impStr := strconv.Itoa(extImp.ImpID) + + resolvedUrl := strings.ReplaceAll(a.endpoint, pageIDMacro, url.QueryEscape(pageStr)) + resolvedUrl = strings.ReplaceAll(resolvedUrl, impIDMacro, url.QueryEscape(impStr)) + + if referer != "" { + resolvedUrl += "&target-ref=" + url.QueryEscape(referer) + } + + if cur != "" { + resolvedUrl += "&ssp-cur=" + cur + } + + return resolvedUrl +} + +func buildRequestData(bidRequest openrtb2.BidRequest, uri string) (*adapters.RequestData, error) { + body, err := jsonutil.Marshal(bidRequest) + if err != nil { + return nil, err + } + + headers := http.Header{} + headers.Add("Content-Type", "application/json;charset=utf-8") + headers.Add("Accept", "application/json") + + if bidRequest.Device != nil { + if bidRequest.Device.UA != "" { + headers.Add("User-Agent", bidRequest.Device.UA) + } + if bidRequest.Device.IP != "" { + headers.Add("X-Forwarded-For", bidRequest.Device.IP) + headers.Add("X-Real-Ip", bidRequest.Device.IP) + } + if bidRequest.Device.Language != "" { + headers.Add("Accept-Language", bidRequest.Device.Language) + } + } + return &adapters.RequestData{ + Method: http.MethodPost, + Uri: uri, + Body: body, + Headers: headers, + ImpIDs: openrtb_ext.GetImpIDs(bidRequest.Imp), + }, nil +} + +func getReferer(request *openrtb2.BidRequest) string { + if request.Site != nil { + return request.Site.Page + } + return "" +} + +func getCur(request *openrtb2.BidRequest) string { + if len(request.Cur) > 0 { + return request.Cur[0] + } + return "" +} + +func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) { + if adapters.IsResponseStatusCodeNoContent(responseData) { + return nil, nil + } + + if err := adapters.CheckResponseStatusCodeForErrors(responseData); err != nil { + return nil, []error{err} + } + + var response openrtb2.BidResponse + if err := jsonutil.Unmarshal(responseData.Body, &response); err != nil { + return nil, []error{err} + } + + bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(request.Imp)) + if len(response.Cur) != 0 { + bidResponse.Currency = response.Cur + } + + for _, seatBid := range response.SeatBid { + for i := range seatBid.Bid { + bid := seatBid.Bid[i] + bidType, err := getBidType(bid) + if err != nil { + return nil, []error{err} + } + + b := &adapters.TypedBid{ + Bid: &seatBid.Bid[i], + BidType: bidType, + } + bidResponse.Bids = append(bidResponse.Bids, b) + } + } + return bidResponse, nil +} + +func getBidType(bid openrtb2.Bid) (openrtb_ext.BidType, error) { + switch bid.MType { + case openrtb2.MarkupBanner: + return openrtb_ext.BidTypeBanner, nil + case openrtb2.MarkupNative: + return openrtb_ext.BidTypeNative, nil + } + + return "", fmt.Errorf("could not define media type for impression: %s", bid.ImpID) +} diff --git a/adapters/intertech/intertech_test.go b/adapters/intertech/intertech_test.go new file mode 100644 index 00000000000..952b2a4431c --- /dev/null +++ b/adapters/intertech/intertech_test.go @@ -0,0 +1,21 @@ +package intertech + +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.BidderIntertech, config.Adapter{ + Endpoint: "https://test.intertech.com/ssp?pid={{page_id}}&imp={{imp_id}}"}, config.Server{ + ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "intertechtest", bidder) +} diff --git a/adapters/intertech/intertechtest/exemplary/simple-banner-muli-format.json b/adapters/intertech/intertechtest/exemplary/simple-banner-muli-format.json new file mode 100644 index 00000000000..39f12626289 --- /dev/null +++ b/adapters/intertech/intertechtest/exemplary/simple-banner-muli-format.json @@ -0,0 +1,115 @@ +{ + "mockBidRequest": { + "id": "request-id-1", + "device": { + "ip": "123.123.123.123", + "ua": "Mozilla/5.0 (X11; Linux x86_64)" + }, + "site": { + "page": "http://bannercheck.com" + }, + "imp": [ + { + "id": "imp-id-1", + "tagid": "tag-id-1", + "banner": { + "format": [ + { "w": 728, "h": 90 }, + { "w": 300, "h": 250 } + ] + }, + "ext": { + "bidder": { + "page_id": 1111, + "imp_id": 2222 + } + } + } + ], + "cur": ["USD"] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://test.intertech.com/ssp?pid=1111&imp=2222&target-ref=http%3A%2F%2Fbannercheck.com&ssp-cur=USD", + "body": { + "id": "request-id-1", + "imp": [ + { + "id": "imp-id-1", + "tagid": "tag-id-1", + "banner": { + "w": 728, + "h": 90, + "format": [ + { "w": 728, "h": 90 }, + { "w": 300, "h": 250 } + ] + }, + "ext": { + "bidder": { + "page_id": 1111, + "imp_id": 2222 + } + } + } + ], + "site": { + "page": "http://bannercheck.com" + }, + "device": { + "ip": "123.123.123.123", + "ua": "Mozilla/5.0 (X11; Linux x86_64)" + }, + "cur": ["USD"] + }, + "impIDs": ["imp-id-1"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "request-id-1", + "cur": "USD", + "seatbid": [ + { + "seat": "intertech", + "bid": [ + { + "id": "bid-id-1", + "impid": "imp-id-1", + "price": 0.7, + "adm": "

Test Banner 728x90

", + "cid": "campaign-id-1", + "crid": "creative-id-1", + "w": 728, + "h": 90, + "mtype": 1 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "bid-id-1", + "impid": "imp-id-1", + "price": 0.7, + "adm": "

Test Banner 728x90

", + "cid": "campaign-id-1", + "crid": "creative-id-1", + "w": 728, + "h": 90, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/intertech/intertechtest/exemplary/simple-banner.json b/adapters/intertech/intertechtest/exemplary/simple-banner.json new file mode 100644 index 00000000000..dc0473465af --- /dev/null +++ b/adapters/intertech/intertechtest/exemplary/simple-banner.json @@ -0,0 +1,119 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "ip": "123.123.123.123", + "ua": "Mozilla/5.0 (iPad; CPU OS 10_3 like Mac OS X)", + "language": "en-US" + }, + "site": { + "page": "mypage" + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "test-tag", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "page_id": 1001, + "imp_id": 2002 + } + } + } + ], + "cur": ["USD"] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://test.intertech.com/ssp?pid=1001&imp=2002&target-ref=mypage&ssp-cur=USD", + "headers": { + "Content-Type": ["application/json;charset=utf-8"], + "Accept": ["application/json"], + "Accept-Language": ["en-US"], + "User-Agent": ["Mozilla/5.0 (iPad; CPU OS 10_3 like Mac OS X)"], + "X-Forwarded-For": ["123.123.123.123"], + "X-Real-Ip": ["123.123.123.123"] + }, + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "tagid": "test-tag", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "page_id": 1001, + "imp_id": 2002 + } + } + } + ], + "site": { + "page": "mypage" + }, + "device": { + "ip": "123.123.123.123", + "ua": "Mozilla/5.0 (iPad; CPU OS 10_3 like Mac OS X)", + "language": "en-US" + }, + "cur": ["USD"] + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "cur": "USD", + "seatbid": [ + { + "seat": "intertech", + "bid": [ + { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.5, + "adm": "

Test Ad

", + "cid": "test_cid", + "crid": "test_crid", + "w": 300, + "h": 250, + "mtype": 1 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.5, + "adm": "

Test Ad

", + "cid": "test_cid", + "crid": "test_crid", + "w": 300, + "h": 250, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/intertech/intertechtest/exemplary/simple-native.json b/adapters/intertech/intertechtest/exemplary/simple-native.json new file mode 100644 index 00000000000..a9336b8ffb1 --- /dev/null +++ b/adapters/intertech/intertechtest/exemplary/simple-native.json @@ -0,0 +1,103 @@ +{ + "mockBidRequest": { + "id": "test-native-request-id", + "device": { + "ip": "123.123.123.123", + "ua": "Mozilla/5.0 (iPhone; CPU iPhone OS 10_3 like Mac OS X)" + }, + "site": { + "page": "nativepage" + }, + "imp": [ + { + "id": "test-native-imp-id", + "tagid": "test-native-tag", + "native": { + "request": "{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":25}}],\"eventtrackers\":[{\"event\":1,\"method\":1}],\"ver\":\"1.2\"}" + }, + "ext": { + "bidder": { + "page_id": 3003, + "imp_id": 4004 + } + } + } + ], + "cur": ["USD"] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://test.intertech.com/ssp?pid=3003&imp=4004&target-ref=nativepage&ssp-cur=USD", + "body": { + "id": "test-native-request-id", + "imp": [ + { + "id": "test-native-imp-id", + "tagid": "test-native-tag", + "native": { + "request": "{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":25}}],\"eventtrackers\":[{\"event\":1,\"method\":1}],\"ver\":\"1.2\"}" + }, + "ext": { + "bidder": { + "page_id": 3003, + "imp_id": 4004 + } + } + } + ], + "site": { + "page": "nativepage" + }, + "device": { + "ip": "123.123.123.123", + "ua": "Mozilla/5.0 (iPhone; CPU iPhone OS 10_3 like Mac OS X)" + }, + "cur": ["USD"] + }, + "impIDs": ["test-native-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-native-request-id", + "cur": "USD", + "seatbid": [ + { + "seat": "intertech", + "bid": [ + { + "id": "test_native_bid_id", + "impid": "test-native-imp-id", + "price": 1.0, + "adm": "{\"native\":{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"title\":{\"text\":\"Test Native Title\"}}],\"link\":{\"url\":\"http://example.com\"},\"imptrackers\":[\"http://example.com/imp\"]}}", + "cid": "test_native_cid", + "crid": "test_native_crid", + "mtype": 4 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "test_native_bid_id", + "impid": "test-native-imp-id", + "price": 1.0, + "adm": "{\"native\":{\"ver\":\"1.2\",\"assets\":[{\"id\":1,\"title\":{\"text\":\"Test Native Title\"}}],\"link\":{\"url\":\"http://example.com\"},\"imptrackers\":[\"http://example.com/imp\"]}}", + "cid": "test_native_cid", + "crid": "test_native_crid", + "mtype": 4 + }, + "type": "native" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/intertech/intertechtest/supplemental/bad_media_type.json b/adapters/intertech/intertechtest/supplemental/bad_media_type.json new file mode 100644 index 00000000000..4e1074f136c --- /dev/null +++ b/adapters/intertech/intertechtest/supplemental/bad_media_type.json @@ -0,0 +1,100 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "ip": "123.123.123.123", + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" + }, + "site": { + "page": "http://example.com" + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "test-tag", + "banner": { + "format": [ + { "w": 300, "h": 250 } + ] + }, + "ext": { + "bidder": { + "page_id": 3003, + "imp_id": 5005 + } + } + } + ], + "cur": ["USD"] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://test.intertech.com/ssp?pid=3003&imp=5005&target-ref=http%3A%2F%2Fexample.com&ssp-cur=USD", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "tagid": "test-tag", + "banner": { + "w": 300, + "h": 250, + "format": [ + { "w": 300, "h": 250 } + ] + }, + "ext": { + "bidder": { + "page_id": 3003, + "imp_id": 5005 + } + } + } + ], + "site": { + "page": "http://example.com" + }, + "device": { + "ip": "123.123.123.123", + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" + }, + "cur": ["USD"] + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "cur": "USD", + "seatbid": [ + { + "seat": "intertech", + "bid": [ + { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.5, + "adm": "

Test Ad

", + "cid": "test_cid", + "crid": "test_crid", + "w": 300, + "h": 250, + "mtype": 2 + } + ] + } + ] + } + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "could not define media type for impression: test-imp-id", + "comparison": "literal" + } + ] + } + \ No newline at end of file diff --git a/adapters/intertech/intertechtest/supplemental/bad_response.json b/adapters/intertech/intertechtest/supplemental/bad_response.json new file mode 100644 index 00000000000..6ca58d71dd9 --- /dev/null +++ b/adapters/intertech/intertechtest/supplemental/bad_response.json @@ -0,0 +1,79 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "ip": "123.123.123.123", + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" + }, + "site": { + "page": "http://example.com" + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "test-tag", + "banner": { + "format": [ + { "w": 300, "h": 250 } + ] + }, + "ext": { + "bidder": { + "page_id": 1001, + "imp_id": 2002 + } + } + } + ], + "cur": ["USD"] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://test.intertech.com/ssp?pid=1001&imp=2002&target-ref=http%3A%2F%2Fexample.com&ssp-cur=USD", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "tagid": "test-tag", + "banner": { + "w": 300, + "h": 250, + "format": [ + { "w": 300, "h": 250 } + ] + }, + "ext": { + "bidder": { + "page_id": 1001, + "imp_id": 2002 + } + } + } + ], + "site": { + "page": "http://example.com" + }, + "device": { + "ip": "123.123.123.123", + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" + }, + "cur": ["USD"] + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": "" + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "expect { or n, but found \"", + "comparison": "literal" + } + ] + } + \ No newline at end of file diff --git a/adapters/intertech/intertechtest/supplemental/invalid-banner-size.json b/adapters/intertech/intertechtest/supplemental/invalid-banner-size.json new file mode 100644 index 00000000000..49d6a4996cf --- /dev/null +++ b/adapters/intertech/intertechtest/supplemental/invalid-banner-size.json @@ -0,0 +1,35 @@ +{ + "mockBidRequest": { + "id": "test-invalid-sizes-request-id", + "device": { + "ip": "123.123.123.123", + "ua": "Mozilla/5.0 (X11; Linux x86_64)" + }, + "site": { + "page": "http://no-size-banner.com" + }, + "imp": [ + { + "id": "test-imp-no-size", + "tagid": "no-size-tag", + "banner": { + "format": [] + }, + "ext": { + "bidder": { + "page_id": 1111, + "imp_id": 9999 + } + } + } + ], + "cur": ["USD"] + }, + "httpCalls": [], + "expectedMakeRequestsErrors": [ + { + "value": "imp #test-imp-no-size: Invalid sizes provided for Banner", + "comparison": "literal" + } + ] +} diff --git a/adapters/intertech/intertechtest/supplemental/invalid-bidder.json b/adapters/intertech/intertechtest/supplemental/invalid-bidder.json new file mode 100644 index 00000000000..0f530a0e68c --- /dev/null +++ b/adapters/intertech/intertechtest/supplemental/invalid-bidder.json @@ -0,0 +1,28 @@ +{ + "mockBidRequest": { + "id": "test-req-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": "badBidder" + } + } + ] + }, + + "expectedMakeRequestsErrors": [ + { + "value": "imp #test-imp-id: unable to parse intertech ext: expect { or n, but found \"", + "comparison": "literal" + } + ] +} diff --git a/adapters/intertech/intertechtest/supplemental/invalid-ext.json b/adapters/intertech/intertechtest/supplemental/invalid-ext.json new file mode 100644 index 00000000000..4c8eb9c9c7c --- /dev/null +++ b/adapters/intertech/intertechtest/supplemental/invalid-ext.json @@ -0,0 +1,30 @@ +{ + "mockBidRequest": { + "id": "test-req-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": 123 + } + ] + }, + + "httpCalls": [], + + "expectedBidResponses": [], + + "expectedMakeRequestsErrors": [ + { + "value": "imp #test-imp-id: unable to parse bidder ext: expect { or n, but found 1", + "comparison": "literal" + } + ] +} diff --git a/adapters/intertech/intertechtest/supplemental/no-cur-req.json b/adapters/intertech/intertechtest/supplemental/no-cur-req.json new file mode 100644 index 00000000000..a6101b6023c --- /dev/null +++ b/adapters/intertech/intertechtest/supplemental/no-cur-req.json @@ -0,0 +1,71 @@ +{ + "mockBidRequest": { + "id": "test-no-cur-request-id", + "device": { + "ip": "123.123.123.123", + "ua": "Mozilla/5.0 (X11; Linux x86_64)" + }, + "site": { + "page": "http://example-nocur.com" + }, + "imp": [ + { + "id": "test-imp-no-cur", + "tagid": "no-cur-tag", + "banner": { + "format": [ + { "w": 300, "h": 250 } + ] + }, + "ext": { + "bidder": { + "page_id": 1111, + "imp_id": 2222 + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://test.intertech.com/ssp?pid=1111&imp=2222&target-ref=http%3A%2F%2Fexample-nocur.com", + "body": { + "id": "test-no-cur-request-id", + "imp": [ + { + "id": "test-imp-no-cur", + "tagid": "no-cur-tag", + "banner": { + "w": 300, + "h": 250, + "format": [ + { "w": 300, "h": 250 } + ] + }, + "ext": { + "bidder": { + "page_id": 1111, + "imp_id": 2222 + } + } + } + ], + "site": { + "page": "http://example-nocur.com" + }, + "device": { + "ip": "123.123.123.123", + "ua": "Mozilla/5.0 (X11; Linux x86_64)" + } + }, + "impIDs": ["test-imp-no-cur"] + }, + "mockResponse": { + "status": 204, + "body": {} + } + } + ], + "expectedBidResponses": [] +} diff --git a/adapters/intertech/intertechtest/supplemental/no-device.json b/adapters/intertech/intertechtest/supplemental/no-device.json new file mode 100644 index 00000000000..8f811e0709c --- /dev/null +++ b/adapters/intertech/intertechtest/supplemental/no-device.json @@ -0,0 +1,105 @@ +{ + "mockBidRequest": { + "id": "test-request-no-device", + "site": { + "page": "mypage" + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "test-tag", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "page_id": 1001, + "imp_id": 2002 + } + } + } + ], + "cur": ["USD"] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://test.intertech.com/ssp?pid=1001&imp=2002&target-ref=mypage&ssp-cur=USD", + "headers": { + "Content-Type": ["application/json;charset=utf-8"], + "Accept": ["application/json"] + }, + "body": { + "id": "test-request-no-device", + "imp": [ + { + "id": "test-imp-id", + "tagid": "test-tag", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "page_id": 1001, + "imp_id": 2002 + } + } + } + ], + "site": { + "page": "mypage" + }, + "cur": ["USD"] + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-no-device", + "cur": "USD", + "seatbid": [ + { + "seat": "intertech", + "bid": [ + { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.5, + "adm": "

Test Ad

", + "cid": "test_cid", + "crid": "test_crid", + "w": 300, + "h": 250, + "mtype": 1 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.5, + "adm": "

Test Ad

", + "cid": "test_cid", + "crid": "test_crid", + "w": 300, + "h": 250, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/intertech/intertechtest/supplemental/no-site-req.json b/adapters/intertech/intertechtest/supplemental/no-site-req.json new file mode 100644 index 00000000000..9d4901994bb --- /dev/null +++ b/adapters/intertech/intertechtest/supplemental/no-site-req.json @@ -0,0 +1,67 @@ +{ + "mockBidRequest": { + "id": "test-no-site-request-id", + "device": { + "ip": "123.123.123.123", + "ua": "Mozilla/5.0 (X11; Linux x86_64)" + }, + "imp": [ + { + "id": "test-imp-no-site", + "tagid": "no-site-tag", + "banner": { + "format": [ + { "w": 300, "h": 250 } + ] + }, + "ext": { + "bidder": { + "page_id": 3003, + "imp_id": 5005 + } + } + } + ], + "cur": ["USD"] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://test.intertech.com/ssp?pid=3003&imp=5005&ssp-cur=USD", + "body": { + "id": "test-no-site-request-id", + "imp": [ + { + "id": "test-imp-no-site", + "tagid": "no-site-tag", + "banner": { + "w": 300, + "h": 250, + "format": [ + { "w": 300, "h": 250 } + ] + }, + "ext": { + "bidder": { + "page_id": 3003, + "imp_id": 5005 + } + } + } + ], + "device": { + "ip": "123.123.123.123", + "ua": "Mozilla/5.0 (X11; Linux x86_64)" + }, + "cur": ["USD"] + }, + "impIDs": ["test-imp-no-site"] + }, + "mockResponse": { + "status": 204, + "body": {} + } + } + ], + "expectedBidResponses": [] +} diff --git a/adapters/intertech/intertechtest/supplemental/status-204.json b/adapters/intertech/intertechtest/supplemental/status-204.json new file mode 100644 index 00000000000..8225c9ea57d --- /dev/null +++ b/adapters/intertech/intertechtest/supplemental/status-204.json @@ -0,0 +1,73 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "ip": "123.123.123.123", + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" + }, + "site": { + "page": "http://example.com" + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "test-tag", + "banner": { + "format": [ + { "w": 300, "h": 250 } + ] + }, + "ext": { + "bidder": { + "page_id": 1001, + "imp_id": 2002 + } + } + } + ], + "cur": ["USD"] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://test.intertech.com/ssp?pid=1001&imp=2002&target-ref=http%3A%2F%2Fexample.com&ssp-cur=USD", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "tagid": "test-tag", + "banner": { + "w": 300, + "h": 250, + "format": [ + { "w": 300, "h": 250 } + ] + }, + "ext": { + "bidder": { + "page_id": 1001, + "imp_id": 2002 + } + } + } + ], + "site": { + "page": "http://example.com" + }, + "device": { + "ip": "123.123.123.123", + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" + }, + "cur": ["USD"] + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 204, + "body": {} + } + } + ], + "expectedBidResponses": [] +} diff --git a/adapters/intertech/intertechtest/supplemental/status-not-200.json b/adapters/intertech/intertechtest/supplemental/status-not-200.json new file mode 100644 index 00000000000..58317e359fd --- /dev/null +++ b/adapters/intertech/intertechtest/supplemental/status-not-200.json @@ -0,0 +1,78 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "ip": "123.123.123.123", + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" + }, + "site": { + "page": "http://mypage.com" + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "test-tag", + "banner": { + "format": [ + { "w": 300, "h": 250 } + ] + }, + "ext": { + "bidder": { + "page_id": 1001, + "imp_id": 2002 + } + } + } + ], + "cur": ["USD"] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://test.intertech.com/ssp?pid=1001&imp=2002&target-ref=http%3A%2F%2Fmypage.com&ssp-cur=USD", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "tagid": "test-tag", + "banner": { + "w": 300, + "h": 250, + "format": [ + { "w": 300, "h": 250 } + ] + }, + "ext": { + "bidder": { + "page_id": 1001, + "imp_id": 2002 + } + } + } + ], + "site": { + "page": "http://mypage.com" + }, + "device": { + "ip": "123.123.123.123", + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" + }, + "cur": ["USD"] + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 404, + "body": {} + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 404. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] +} diff --git a/adapters/intertech/params_test.go b/adapters/intertech/params_test.go new file mode 100644 index 00000000000..eb7bb0aba4e --- /dev/null +++ b/adapters/intertech/params_test.go @@ -0,0 +1,48 @@ +package intertech + +import ( + "encoding/json" + "testing" + + "github.com/prebid/prebid-server/v3/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 _, p := range validParams { + if err := validator.Validate(openrtb_ext.BidderIntertech, json.RawMessage(p)); err != nil { + t.Errorf("Schema rejected valid params: %s", p) + } + } +} + +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 _, p := range invalidParams { + if err := validator.Validate(openrtb_ext.BidderIntertech, json.RawMessage(p)); err == nil { + t.Errorf("Schema allowed invalid params: %s", p) + } + } +} + +var validParams = []string{ + `{"page_id": 123, "imp_id": 456}`, + `{"page_id": 1, "imp_id": 1}`, + `{"page_id": 999, "imp_id": 999}`, +} + +var invalidParams = []string{ + `{"page_id": "abc", "imp_id": 1}`, + `{"page_id": "1", "imp_id": abc}`, + `{"page_id": "123123"}`, + `{"imp_id": "123"}`, + `{}`, +} diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index 67e28286f03..a0f0ada560d 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -110,6 +110,7 @@ import ( "github.com/prebid/prebid-server/v3/adapters/infytv" "github.com/prebid/prebid-server/v3/adapters/inmobi" "github.com/prebid/prebid-server/v3/adapters/interactiveoffers" + "github.com/prebid/prebid-server/v3/adapters/intertech" "github.com/prebid/prebid-server/v3/adapters/invibes" "github.com/prebid/prebid-server/v3/adapters/iqx" "github.com/prebid/prebid-server/v3/adapters/iqzone" @@ -340,6 +341,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderInfyTV: infytv.Builder, openrtb_ext.BidderInMobi: inmobi.Builder, openrtb_ext.BidderInteractiveoffers: interactiveoffers.Builder, + openrtb_ext.BidderIntertech: intertech.Builder, openrtb_ext.BidderInvibes: invibes.Builder, openrtb_ext.BidderIQX: iqx.Builder, openrtb_ext.BidderIQZone: iqzone.Builder, diff --git a/macros/macros.go b/macros/macros.go index 2b0e29d6238..1fff558b39c 100644 --- a/macros/macros.go +++ b/macros/macros.go @@ -17,6 +17,7 @@ type EndpointTemplateParams struct { GvlID string PageID string SupplyId string + ImpID string SspId string SspID string SeatID string diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index f7706ce5c25..94fe8932e84 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -127,6 +127,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderInfyTV, BidderInMobi, BidderInteractiveoffers, + BidderIntertech, BidderInvibes, BidderIQX, BidderIQZone, @@ -456,6 +457,7 @@ const ( BidderInfyTV BidderName = "infytv" BidderInMobi BidderName = "inmobi" BidderInteractiveoffers BidderName = "interactiveoffers" + BidderIntertech BidderName = "intertech" BidderInvibes BidderName = "invibes" BidderIQX BidderName = "iqx" BidderIQZone BidderName = "iqzone" diff --git a/openrtb_ext/imp_intertech.go b/openrtb_ext/imp_intertech.go new file mode 100644 index 00000000000..7c0bc955c5a --- /dev/null +++ b/openrtb_ext/imp_intertech.go @@ -0,0 +1,6 @@ +package openrtb_ext + +type ExtImpIntertech struct { + PageID int `json:"page_id"` + ImpID int `json:"imp_id"` +} diff --git a/static/bidder-info/intertech.yaml b/static/bidder-info/intertech.yaml new file mode 100644 index 00000000000..bf4b52bc382 --- /dev/null +++ b/static/bidder-info/intertech.yaml @@ -0,0 +1,15 @@ +# This adapter is ported from PBS-Java to PBS-Go by Prebid. Please open a GitHub issue instead of +# directly contacting the maintainer for technical issues. +endpoint: https://prebid.intertechsrvcs.com/prebid/{{.PageID}}?imp-id={{.ImpID}}&ssp-id=10500 +endpointCompression: GZIP +maintainer: + email: prebid@intertechsrvcs.com +capabilities: + site: + mediaTypes: + - banner + - native +userSync: + redirect: + url: https://prebid.intertechsrvcs.com/mapuid/intertech/?ssp-id=10500&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&location= + userMacro: "{UID}" \ No newline at end of file diff --git a/static/bidder-params/intertech.json b/static/bidder-params/intertech.json new file mode 100644 index 00000000000..8b1e3daa6cd --- /dev/null +++ b/static/bidder-params/intertech.json @@ -0,0 +1,21 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Intertech Adapter Params", + "description": "A schema which validates params accepted by the Intertech adapter", + "type": "object", + "properties": { + "page_id": { + "type": "integer", + "minLength": 1, + "description": "Special Page Id provided by Intertech Manager" + }, + "imp_id": { + "type": "integer", + "minLength": 1, + "description": "Special identifier provided by Intertech Manager" + } + }, + "required": + ["page_id", + "imp_id"] +} \ No newline at end of file