diff --git a/account/account.go b/account/account.go new file mode 100644 index 00000000000..2f27b61efab --- /dev/null +++ b/account/account.go @@ -0,0 +1,69 @@ +package account + +import ( + "context" + "encoding/json" + "fmt" + + jsonpatch "github.com/evanphx/json-patch" + "github.com/prebid/prebid-server/config" + "github.com/prebid/prebid-server/errortypes" + "github.com/prebid/prebid-server/pbsmetrics" + "github.com/prebid/prebid-server/stored_requests" +) + +// GetAccount looks up the config.Account object referenced by the given accountID, with access rules applied +func GetAccount(ctx context.Context, cfg *config.Configuration, fetcher stored_requests.AccountFetcher, accountID string) (account *config.Account, errs []error) { + // Check BlacklistedAcctMap until we have deprecated it + if _, found := cfg.BlacklistedAcctMap[accountID]; found { + return nil, []error{&errortypes.BlacklistedAcct{ + Message: fmt.Sprintf("Prebid-server has disabled Account ID: %s, please reach out to the prebid server host.", accountID), + }} + } + if cfg.AccountRequired && accountID == pbsmetrics.PublisherUnknown { + return nil, []error{&errortypes.AcctRequired{ + Message: fmt.Sprintf("Prebid-server has been configured to discard requests without a valid Account ID. Please reach out to the prebid server host."), + }} + } + if accountJSON, accErrs := fetcher.FetchAccount(ctx, accountID); len(accErrs) > 0 || accountJSON == nil { + // accountID does not reference a valid account + for _, e := range accErrs { + if _, ok := e.(stored_requests.NotFoundError); !ok { + errs = append(errs, e) + } + } + if cfg.AccountRequired && cfg.AccountDefaults.Disabled { + errs = append(errs, &errortypes.AcctRequired{ + Message: fmt.Sprintf("Prebid-server could not verify the Account ID. Please reach out to the prebid server host."), + }) + return nil, errs + } + // Make a copy of AccountDefaults instead of taking a reference, + // to preserve original accountID in case is needed to check NonStandardPublisherMap + pubAccount := cfg.AccountDefaults + pubAccount.ID = accountID + account = &pubAccount + } else { + // accountID resolved to a valid account, merge with AccountDefaults for a complete config + account = &config.Account{} + completeJSON, err := jsonpatch.MergePatch(cfg.AccountDefaultsJSON(), accountJSON) + if err == nil { + err = json.Unmarshal(completeJSON, account) + } + if err != nil { + errs = append(errs, err) + return nil, errs + } + // Fill in ID if needed, so it can be left out of account definition + if len(account.ID) == 0 { + account.ID = accountID + } + } + if account.Disabled { + errs = append(errs, &errortypes.BlacklistedAcct{ + Message: fmt.Sprintf("Prebid-server has disabled Account ID: %s, please reach out to the prebid server host.", accountID), + }) + return nil, errs + } + return account, nil +} diff --git a/account/account_test.go b/account/account_test.go new file mode 100644 index 00000000000..0d192f18510 --- /dev/null +++ b/account/account_test.go @@ -0,0 +1,94 @@ +package account + +import ( + "context" + "encoding/json" + "fmt" + "testing" + + "github.com/prebid/prebid-server/config" + "github.com/prebid/prebid-server/errortypes" + "github.com/prebid/prebid-server/pbsmetrics" + "github.com/prebid/prebid-server/stored_requests" + "github.com/stretchr/testify/assert" +) + +var mockAccountData = map[string]json.RawMessage{ + "valid_acct": json.RawMessage(`{"disabled":false}`), + "disabled_acct": json.RawMessage(`{"disabled":true}`), +} + +type mockAccountFetcher struct { +} + +func (af mockAccountFetcher) FetchAccount(ctx context.Context, accountID string) (json.RawMessage, []error) { + if account, ok := mockAccountData[accountID]; ok { + return account, nil + } + return nil, []error{stored_requests.NotFoundError{accountID, "Account"}} +} + +func TestGetAccount(t *testing.T) { + unknown := pbsmetrics.PublisherUnknown + testCases := []struct { + accountID string + // account_required + required bool + // account_defaults.disabled + disabled bool + // expected error, or nil if account should be found + err error + }{ + // Blacklisted account is always rejected even in permissive setup + {accountID: "bad_acct", required: false, disabled: false, err: &errortypes.BlacklistedAcct{}}, + + // empty pubID + {accountID: unknown, required: false, disabled: false, err: nil}, + {accountID: unknown, required: true, disabled: false, err: &errortypes.AcctRequired{}}, + {accountID: unknown, required: false, disabled: true, err: &errortypes.BlacklistedAcct{}}, + {accountID: unknown, required: true, disabled: true, err: &errortypes.AcctRequired{}}, + + // pubID given but is not a valid host account (does not exist) + {accountID: "doesnt_exist_acct", required: false, disabled: false, err: nil}, + {accountID: "doesnt_exist_acct", required: true, disabled: false, err: nil}, + {accountID: "doesnt_exist_acct", required: false, disabled: true, err: &errortypes.BlacklistedAcct{}}, + {accountID: "doesnt_exist_acct", required: true, disabled: true, err: &errortypes.AcctRequired{}}, + + // pubID given and matches a valid host account with Disabled: false + {accountID: "valid_acct", required: false, disabled: false, err: nil}, + {accountID: "valid_acct", required: true, disabled: false, err: nil}, + {accountID: "valid_acct", required: false, disabled: true, err: nil}, + {accountID: "valid_acct", required: true, disabled: true, err: nil}, + + // pubID given and matches a host account explicitly disabled (Disabled: true on account json) + {accountID: "disabled_acct", required: false, disabled: false, err: &errortypes.BlacklistedAcct{}}, + {accountID: "disabled_acct", required: true, disabled: false, err: &errortypes.BlacklistedAcct{}}, + {accountID: "disabled_acct", required: false, disabled: true, err: &errortypes.BlacklistedAcct{}}, + {accountID: "disabled_acct", required: true, disabled: true, err: &errortypes.BlacklistedAcct{}}, + } + + for _, test := range testCases { + description := fmt.Sprintf(`ID=%s/required=%t/disabled=%t`, test.accountID, test.required, test.disabled) + t.Run(description, func(t *testing.T) { + cfg := &config.Configuration{ + BlacklistedAcctMap: map[string]bool{"bad_acct": true}, + AccountRequired: test.required, + AccountDefaults: config.Account{Disabled: test.disabled}, + } + fetcher := &mockAccountFetcher{} + assert.NoError(t, cfg.MarshalAccountDefaults()) + + account, errors := GetAccount(context.Background(), cfg, fetcher, test.accountID) + + if test.err == nil { + assert.Empty(t, errors) + assert.Equal(t, test.accountID, account.ID, "account.ID must match requested ID") + assert.Equal(t, false, account.Disabled, "returned account must not be disabled") + } else { + assert.NotEmpty(t, errors, "expected errors but got success") + assert.Nil(t, account, "return account must be nil on error") + assert.IsType(t, test.err, errors[0], "error is of unexpected type") + } + }) + } +} diff --git a/adapters/colossus/colossus.go b/adapters/colossus/colossus.go new file mode 100644 index 00000000000..89cd49d2881 --- /dev/null +++ b/adapters/colossus/colossus.go @@ -0,0 +1,137 @@ +package colossus + +import ( + "encoding/json" + "fmt" + "net/http" + + "github.com/buger/jsonparser" + "github.com/mxmCherry/openrtb" + "github.com/prebid/prebid-server/adapters" + "github.com/prebid/prebid-server/errortypes" + "github.com/prebid/prebid-server/openrtb_ext" +) + +type ColossusAdapter struct { + URI string +} + +// NewColossusBidder Initializes the Bidder +func NewColossusBidder(endpoint string) *ColossusAdapter { + return &ColossusAdapter{ + URI: endpoint, + } +} + +// MakeRequests create bid request for colossus demand +func (a *ColossusAdapter) MakeRequests(request *openrtb.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { + var errs []error + var err error + var tagID string + + var adapterRequests []*adapters.RequestData + + reqCopy := *request + for _, imp := range request.Imp { + reqCopy.Imp = []openrtb.Imp{imp} + + tagID, err = jsonparser.GetString(reqCopy.Imp[0].Ext, "bidder", "TagID") + if err != nil { + errs = append(errs, err) + continue + } + + reqCopy.Imp[0].TagID = tagID + + adapterReq, errors := a.makeRequest(&reqCopy) + if adapterReq != nil { + adapterRequests = append(adapterRequests, adapterReq) + } + errs = append(errs, errors...) + } + return adapterRequests, errs +} + +func (a *ColossusAdapter) makeRequest(request *openrtb.BidRequest) (*adapters.RequestData, []error) { + + var errs []error + + reqJSON, err := json.Marshal(request) + + if err != nil { + errs = append(errs, err) + return nil, errs + } + + headers := http.Header{} + headers.Add("Content-Type", "application/json;charset=utf-8") + headers.Add("Accept", "application/json") + return &adapters.RequestData{ + Method: "POST", + Uri: a.URI, + Body: reqJSON, + Headers: headers, + }, errs +} + +// MakeBids makes the bids +func (a *ColossusAdapter) MakeBids(internalRequest *openrtb.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) { + var errs []error + + if response.StatusCode == http.StatusNoContent { + return nil, nil + } + + if response.StatusCode == http.StatusNotFound { + return nil, []error{&errortypes.BadServerResponse{ + Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info", response.StatusCode), + }} + } + + if response.StatusCode != http.StatusOK { + return nil, []error{&errortypes.BadServerResponse{ + Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info", response.StatusCode), + }} + } + + var bidResp openrtb.BidResponse + + if err := json.Unmarshal(response.Body, &bidResp); err != nil { + return nil, []error{err} + } + + bidResponse := adapters.NewBidderResponseWithBidsCapacity(1) + + for _, sb := range bidResp.SeatBid { + for i := range sb.Bid { + bidType, err := getMediaTypeForImp(sb.Bid[i].ImpID, internalRequest.Imp) + if err != nil { + errs = append(errs, err) + } else { + b := &adapters.TypedBid{ + Bid: &sb.Bid[i], + BidType: bidType, + } + bidResponse.Bids = append(bidResponse.Bids, b) + } + } + } + return bidResponse, errs +} + +func getMediaTypeForImp(impID string, imps []openrtb.Imp) (openrtb_ext.BidType, error) { + mediaType := openrtb_ext.BidTypeBanner + for _, imp := range imps { + if imp.ID == impID { + if imp.Banner == nil && imp.Video != nil { + mediaType = openrtb_ext.BidTypeVideo + } + return mediaType, nil + } + } + + // This shouldnt happen. Lets handle it just incase by returning an error. + return "", &errortypes.BadInput{ + Message: fmt.Sprintf("Failed to find impression \"%s\" ", impID), + } +} diff --git a/adapters/colossus/colossus_test.go b/adapters/colossus/colossus_test.go new file mode 100644 index 00000000000..f4fd12f3fab --- /dev/null +++ b/adapters/colossus/colossus_test.go @@ -0,0 +1,12 @@ +package colossus + +import ( + "testing" + + "github.com/prebid/prebid-server/adapters/adapterstest" +) + +func TestJsonSamples(t *testing.T) { + colossusAdapter := NewColossusBidder("http://example.com/?c=o&m=rtb") + adapterstest.RunJSONBidderTest(t, "colossustest", colossusAdapter) +} diff --git a/adapters/colossus/colossustest/exemplary/simple-banner.json b/adapters/colossus/colossustest/exemplary/simple-banner.json new file mode 100644 index 00000000000..1adc7010ed8 --- /dev/null +++ b/adapters/colossus/colossustest/exemplary/simple-banner.json @@ -0,0 +1,132 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "tagid": "61317", + "ext": { + "bidder": { + "TagID": "61317" + } + } + } + ], + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "device": { + "ip": "123.123.123.123", + "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx" + } +}, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://example.com/?c=o&m=rtb", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "tagid": "61317", + "ext": { + "bidder": { + "TagID": "61317" + } + } + } + ], + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "device": { + "ip": "123.123.123.123", + "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx" + } + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.27543, + "adm": "", + "cid": "test_cid", + "crid": "test_crid", + "dealid": "test_dealid", + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "banner" + } + } + } + ] + } + ] + } + } + } + ], + + "expectedBidResponses": [ + { + "bids":[ + { + "bid": { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.27543, + "adm": "", + "cid": "test_cid", + "crid": "test_crid", + "dealid": "test_dealid", + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "banner" + } + } + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/colossus/colossustest/exemplary/simple-video.json b/adapters/colossus/colossustest/exemplary/simple-video.json new file mode 100644 index 00000000000..78516fcef31 --- /dev/null +++ b/adapters/colossus/colossustest/exemplary/simple-video.json @@ -0,0 +1,119 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "ip": "123.123.123.123", + "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx" + }, + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": ["video/mp4"], + "protocols": [2, 5], + "w": 1024, + "h": 576 + }, + "ext": { + "bidder": { + "TagID": "61318" + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://example.com/?c=o&m=rtb", + "body": { + "id": "test-request-id", + "device": { + "ip": "123.123.123.123", + "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx" + }, + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": ["video/mp4"], + "protocols": [2, 5], + "w": 1024, + "h": 576 + }, + "tagid": "61318", + "ext": { + "bidder": { + "TagID": "61318" + } + } + } + ] + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.27543, + "adm": "00:01:00", + "cid": "test_cid", + "crid": "test_crid", + "dealid": "test_dealid", + "ext": { + "prebid": { + "type": "video" + } + } + } + ], + "seat": "colossus" + } + ], + "cur": "USD" + } + } + } + ], + + + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.27543, + "adm": "00:01:00", + "cid": "test_cid", + "crid": "test_crid", + "dealid": "test_dealid", + "ext": { + "prebid": { + "type": "video" + } + } + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/colossus/colossustest/exemplary/simple-web-banner.json b/adapters/colossus/colossustest/exemplary/simple-web-banner.json new file mode 100644 index 00000000000..37baf3d97dd --- /dev/null +++ b/adapters/colossus/colossustest/exemplary/simple-web-banner.json @@ -0,0 +1,133 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "tagid": "1", + "ext": { + "bidder": { + "TagID": "1" + } + } + } + ], + "site": { + "id": "1", + "domain": "test.com" + }, + "device": { + "ip": "123.123.123.123" + } + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://example.com/?c=o&m=rtb", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "tagid": "1", + "ext": { + "bidder": { + "TagID": "1" + } + } + } + ], + "site": { + "id": "1", + "domain": "test.com" + }, + "device": { + "ip": "123.123.123.123" + } + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.27543, + "adm": "", + "cid": "test_cid", + "crid": "test_crid", + "dealid": "test_dealid", + "w": 468, + "h": 60, + "ext": { + "prebid": { + "type": "banner" + } + } + } + ], + "seat": "colossus" + } + ], + "cur": "USD" + } + } + } + ], + + "expectedBidResponses": [ + { + "bids":[ + { + "bid": { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.27543, + "adm": "", + "cid": "test_cid", + "crid": "test_crid", + "dealid": "test_dealid", + "w": 468, + "h": 60, + "ext": { + "prebid": { + "type": "banner" + } + } + }, + "type": "banner" + } + ] + } + ] + } + \ No newline at end of file diff --git a/adapters/colossus/colossustest/params/banner.json b/adapters/colossus/colossustest/params/banner.json new file mode 100644 index 00000000000..7c2643d4901 --- /dev/null +++ b/adapters/colossus/colossustest/params/banner.json @@ -0,0 +1,3 @@ +{ + "TagID": "61317" +} diff --git a/adapters/colossus/colossustest/params/race/banner.json b/adapters/colossus/colossustest/params/race/banner.json new file mode 100644 index 00000000000..7c2643d4901 --- /dev/null +++ b/adapters/colossus/colossustest/params/race/banner.json @@ -0,0 +1,3 @@ +{ + "TagID": "61317" +} diff --git a/adapters/colossus/colossustest/params/race/video.json b/adapters/colossus/colossustest/params/race/video.json new file mode 100644 index 00000000000..56f865c71d9 --- /dev/null +++ b/adapters/colossus/colossustest/params/race/video.json @@ -0,0 +1,3 @@ +{ + "TagID": "61318" +} diff --git a/adapters/colossus/colossustest/params/video.json b/adapters/colossus/colossustest/params/video.json new file mode 100644 index 00000000000..56f865c71d9 --- /dev/null +++ b/adapters/colossus/colossustest/params/video.json @@ -0,0 +1,3 @@ +{ + "TagID": "61318" +} diff --git a/adapters/colossus/colossustest/supplemental/bad-imp-ext.json b/adapters/colossus/colossustest/supplemental/bad-imp-ext.json new file mode 100644 index 00000000000..13656337e5e --- /dev/null +++ b/adapters/colossus/colossustest/supplemental/bad-imp-ext.json @@ -0,0 +1,42 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "tagid": "61317", + "ext": { + "colossus": { + "TagID": "61317" + } + } + } + ], + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "device": { + "ip": "123.123.123.123", + "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx" + } +}, +"expectedMakeRequestsErrors": [ + { + "value": "Key path not found", + "comparison": "literal" + } +] +} diff --git a/adapters/colossus/colossustest/supplemental/bad_response.json b/adapters/colossus/colossustest/supplemental/bad_response.json new file mode 100644 index 00000000000..c69b00c8e6e --- /dev/null +++ b/adapters/colossus/colossustest/supplemental/bad_response.json @@ -0,0 +1,85 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "tagid": "17", + "ext": { + "bidder": { + "TagID": "17" + } + } + } + ], + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "device": { + "ip": "123.123.123.123", + "ifa": "sdjfksdf-dfsds-dsdg-dsgg" + } + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "http://example.com/?c=o&m=rtb", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "tagid": "17", + "ext": { + "bidder": { + "TagID": "17" + } + } + } + ], + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "device": { + "ip": "123.123.123.123", + "ifa": "sdjfksdf-dfsds-dsdg-dsgg" + } + } + }, + "mockResponse": { + "status": 200, + "body": "" + } + }], + "expectedMakeBidsErrors": [ + { + "value": "json: cannot unmarshal string into Go value of type openrtb.BidResponse", + "comparison": "literal" + } + ] +} diff --git a/adapters/colossus/colossustest/supplemental/bad_status_code.json b/adapters/colossus/colossustest/supplemental/bad_status_code.json new file mode 100644 index 00000000000..f5b6a5748af --- /dev/null +++ b/adapters/colossus/colossustest/supplemental/bad_status_code.json @@ -0,0 +1,79 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "tagid": "100000000", + "ext": { + "bidder": { + "TagID": "100000000" + } + } + } + ], + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "device": {} + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "http://example.com/?c=o&m=rtb", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "tagid": "100000000", + "ext": { + "bidder": { + "TagID": "100000000" + } + } + } + ], + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "device": {} + } + }, + "mockResponse": { + "status": 400, + "body": {} + } + }], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 400. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] +} diff --git a/adapters/colossus/colossustest/supplemental/empty_imp_ext.json b/adapters/colossus/colossustest/supplemental/empty_imp_ext.json new file mode 100644 index 00000000000..00e1cf60fb7 --- /dev/null +++ b/adapters/colossus/colossustest/supplemental/empty_imp_ext.json @@ -0,0 +1,38 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "tagid": "61317", + "ext": {} + } + ], + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "device": { + "ip": "123.123.123.123", + "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx" + } + }, + "expectedMakeRequestsErrors": [ + { + "value": "Key path not found", + "comparison": "literal" + } + ] +} \ No newline at end of file diff --git a/adapters/colossus/colossustest/supplemental/imp_ext_empty_object.json b/adapters/colossus/colossustest/supplemental/imp_ext_empty_object.json new file mode 100644 index 00000000000..e9c1f257aba --- /dev/null +++ b/adapters/colossus/colossustest/supplemental/imp_ext_empty_object.json @@ -0,0 +1,39 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "tagid": "61317", + "ext": {} + } + ], + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "device": { + "ip": "123.123.123.123", + "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx" + } + }, + "expectedMakeRequestsErrors": [ + { + "value": "Key path not found", + "comparison": "literal" + } + ] + } + \ No newline at end of file diff --git a/adapters/colossus/colossustest/supplemental/imp_ext_string.json b/adapters/colossus/colossustest/supplemental/imp_ext_string.json new file mode 100644 index 00000000000..362a8fa4df8 --- /dev/null +++ b/adapters/colossus/colossustest/supplemental/imp_ext_string.json @@ -0,0 +1,39 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "tagid": "61317", + "ext": "" + } + ], + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "device": { + "ip": "123.123.123.123", + "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx" + } + }, + "expectedMakeRequestsErrors": [ + { + "value": "Key path not found", + "comparison": "literal" + } + ] + } + \ No newline at end of file diff --git a/adapters/colossus/colossustest/supplemental/status-204.json b/adapters/colossus/colossustest/supplemental/status-204.json new file mode 100644 index 00000000000..73f8bc71f23 --- /dev/null +++ b/adapters/colossus/colossustest/supplemental/status-204.json @@ -0,0 +1,79 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "tagid": "17", + "ext": { + "bidder": { + "TagID": "17" + } + } + } + ], + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "device": { + "ip": "123.123.123.123", + "ifa": "sdjfksdf-dfsds-dsdg-dsgg" + } + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "http://example.com/?c=o&m=rtb", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "tagid": "17", + "ext": { + "bidder": { + "TagID": "17" + } + } + } + ], + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "device": { + "ip": "123.123.123.123", + "ifa": "sdjfksdf-dfsds-dsdg-dsgg" + } + } + }, + "mockResponse": { + "status": 204, + "body": {} + } + }] +} diff --git a/adapters/colossus/colossustest/supplemental/status-404.json b/adapters/colossus/colossustest/supplemental/status-404.json new file mode 100644 index 00000000000..676eb8bb2f4 --- /dev/null +++ b/adapters/colossus/colossustest/supplemental/status-404.json @@ -0,0 +1,85 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "tagid": "100000000", + "ext": { + "bidder": { + "TagID": "100000000" + } + } + } + ], + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "device": { + "ip": "123.123.123.123", + "ifa": "sdjfksdf-dfsds-dsdg-dsgg" + } + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "http://example.com/?c=o&m=rtb", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "tagid": "100000000", + "ext": { + "bidder": { + "TagID": "100000000" + } + } + } + ], + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "device": { + "ip": "123.123.123.123", + "ifa": "sdjfksdf-dfsds-dsdg-dsgg" + } + } + }, + "mockResponse": { + "status": 404, + "body": {} + } + }], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 404. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] +} diff --git a/adapters/colossus/colossustest/supplemental/string_imp_ext.json b/adapters/colossus/colossustest/supplemental/string_imp_ext.json new file mode 100644 index 00000000000..362a8fa4df8 --- /dev/null +++ b/adapters/colossus/colossustest/supplemental/string_imp_ext.json @@ -0,0 +1,39 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "tagid": "61317", + "ext": "" + } + ], + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "device": { + "ip": "123.123.123.123", + "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx" + } + }, + "expectedMakeRequestsErrors": [ + { + "value": "Key path not found", + "comparison": "literal" + } + ] + } + \ No newline at end of file diff --git a/adapters/colossus/params_test.go b/adapters/colossus/params_test.go new file mode 100644 index 00000000000..2883de2f53e --- /dev/null +++ b/adapters/colossus/params_test.go @@ -0,0 +1,46 @@ +package colossus + +import ( + "encoding/json" + "testing" + + "github.com/prebid/prebid-server/openrtb_ext" +) + +// TestValidParams makes sure that the colossus 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.BidderColossus, json.RawMessage(validParam)); err != nil { + t.Errorf("Schema rejected colossus params: %s", validParam) + } + } +} + +// TestInvalidParams makes sure that the colossus 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.BidderColossus, json.RawMessage(invalidParam)); err == nil { + t.Errorf("Schema allowed unexpected params: %s", invalidParam) + } + } +} + +var validParams = []string{ + `{"TagID": "61317"}`, +} + +var invalidParams = []string{ + `{"id": "123"}`, + `{"tagid": "123"}`, + `{"TagID": 16}`, +} diff --git a/adapters/colossus/usersync.go b/adapters/colossus/usersync.go new file mode 100644 index 00000000000..a4e82ee3bde --- /dev/null +++ b/adapters/colossus/usersync.go @@ -0,0 +1,13 @@ +package colossus + +import ( + "text/template" + + "github.com/prebid/prebid-server/adapters" + "github.com/prebid/prebid-server/usersync" +) + +// NewColossusSyncer returns colossus syncer +func NewColossusSyncer(temp *template.Template) usersync.Usersyncer { + return adapters.NewSyncer("colossus", 0, temp, adapters.SyncTypeRedirect) +} diff --git a/adapters/colossus/usersync_test.go b/adapters/colossus/usersync_test.go new file mode 100644 index 00000000000..79d5483d528 --- /dev/null +++ b/adapters/colossus/usersync_test.go @@ -0,0 +1,35 @@ +package colossus + +import ( + "testing" + "text/template" + + "github.com/prebid/prebid-server/privacy" + "github.com/prebid/prebid-server/privacy/ccpa" + "github.com/prebid/prebid-server/privacy/gdpr" + "github.com/stretchr/testify/assert" +) + +func TestColossusSyncer(t *testing.T) { + syncURL := "https://sync.colossusssp.com/pbs.gif?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redir=http%3A%2F%2Flocalhost%3A8000%2Fsetuid%3Fbidder%3Dcolossus%26uid%3D%5BUID%5D" + syncURLTemplate := template.Must( + template.New("sync-template").Parse(syncURL), + ) + + syncer := NewColossusSyncer(syncURLTemplate) + syncInfo, err := syncer.GetUsersyncInfo(privacy.Policies{ + GDPR: gdpr.Policy{ + Signal: "0", + Consent: "A", + }, + CCPA: ccpa.Policy{ + Value: "1-YY", + }, + }) + + assert.NoError(t, err) + assert.Equal(t, "https://sync.colossusssp.com/pbs.gif?gdpr=0&gdpr_consent=A&us_privacy=1-YY&redir=http%3A%2F%2Flocalhost%3A8000%2Fsetuid%3Fbidder%3Dcolossus%26uid%3D%5BUID%5D", syncInfo.URL) + assert.Equal(t, "redirect", syncInfo.Type) + assert.EqualValues(t, 0, syncer.GDPRVendorID()) + assert.Equal(t, false, syncInfo.SupportCORS) +} diff --git a/config/config.go b/config/config.go index 59ba55ebe26..5731b65d567 100755 --- a/config/config.go +++ b/config/config.go @@ -693,6 +693,7 @@ func (cfg *Configuration) setDerivedDefaults() { setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderBeachfront, "https://sync.bfmio.com/sync_s2s?gdpr={{.GDPR}}&us_privacy={{.USPrivacy}}&url="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dbeachfront%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%5Bio_cid%5D") setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderBeintoo, "https://ib.beintoo.com/um?ssp=pbs&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dbeintoo%26uid%3D%24UID") setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderBrightroll, "https://pr-bh.ybp.yahoo.com/sync/appnexusprebidserver/?gdpr={{.GDPR}}&euconsent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&url="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dbrightroll%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24UID") + setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderColossus, "https://sync.colossusssp.com/pbs.gif?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redir="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dcolossus%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%5BUID%5D") setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderConsumable, "https://e.serverbid.com/udb/9969/match?gdpr={{.GDPR}}&euconsent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redir="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dconsumable%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D") setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderConversant, "https://prebid-match.dotomi.com/match/bounce/current?version=1&networkId=72582&rurl="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dconversant%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D") setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderCpmstar, "https://server.cpmstar.com/usersync.aspx?gdpr={{.GDPR}}&consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dcpmstar%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24UID") @@ -911,6 +912,7 @@ func SetupViper(v *viper.Viper, filename string) { v.SetDefault("adapters.beachfront.extra_info", "{\"video_endpoint\":\"https://reachms.bfmio.com/bid.json?exchange_id\"}") v.SetDefault("adapters.beintoo.endpoint", "https://ib.beintoo.com/um") v.SetDefault("adapters.brightroll.endpoint", "http://east-bid.ybp.yahoo.com/bid/appnexuspbs") + v.SetDefault("adapters.colossus.endpoint", "http://colossusssp.com/?c=o&m=rtb") v.SetDefault("adapters.consumable.endpoint", "https://e.serverbid.com/api/v2") v.SetDefault("adapters.conversant.endpoint", "http://api.hb.ad.cpe.dotomi.com/cvx/server/hb/ortb/25") v.SetDefault("adapters.cpmstar.endpoint", "https://server.cpmstar.com/openrtbbidrq.aspx") diff --git a/endpoints/openrtb2/amp_auction.go b/endpoints/openrtb2/amp_auction.go index 54f4706902d..1e92569e260 100644 --- a/endpoints/openrtb2/amp_auction.go +++ b/endpoints/openrtb2/amp_auction.go @@ -16,6 +16,7 @@ import ( "github.com/golang/glog" "github.com/julienschmidt/httprouter" "github.com/mxmCherry/openrtb" + accountService "github.com/prebid/prebid-server/account" "github.com/prebid/prebid-server/analytics" "github.com/prebid/prebid-server/config" "github.com/prebid/prebid-server/errortypes" @@ -158,7 +159,7 @@ func (deps *endpointDeps) AmpAuction(w http.ResponseWriter, r *http.Request, _ h } labels.PubID = getAccountID(req.Site.Publisher) // Look up account now that we have resolved the pubID value - account, acctIDErrs := deps.getAccount(ctx, labels.PubID) + account, acctIDErrs := accountService.GetAccount(ctx, deps.cfg, deps.accounts, labels.PubID) if len(acctIDErrs) > 0 { errL = append(errL, acctIDErrs...) httpStatus := http.StatusBadRequest diff --git a/endpoints/openrtb2/auction.go b/endpoints/openrtb2/auction.go index 41c1c1677a5..d6cbc2285fb 100644 --- a/endpoints/openrtb2/auction.go +++ b/endpoints/openrtb2/auction.go @@ -22,6 +22,7 @@ import ( "github.com/mxmCherry/openrtb" "github.com/mxmCherry/openrtb/native" nativeRequests "github.com/mxmCherry/openrtb/native/request" + accountService "github.com/prebid/prebid-server/account" "github.com/prebid/prebid-server/analytics" "github.com/prebid/prebid-server/config" "github.com/prebid/prebid-server/errortypes" @@ -156,7 +157,7 @@ func (deps *endpointDeps) Auction(w http.ResponseWriter, r *http.Request, _ http } // Look up account now that we have resolved the pubID value - account, acctIDErrs := deps.getAccount(ctx, labels.PubID) + account, acctIDErrs := accountService.GetAccount(ctx, deps.cfg, deps.accounts, labels.PubID) if len(acctIDErrs) > 0 { errL = append(errL, acctIDErrs...) writeError(errL, w, &labels) @@ -1317,56 +1318,3 @@ func getAccountID(pub *openrtb.Publisher) string { } return pbsmetrics.PublisherUnknown } - -func (deps *endpointDeps) getAccount(ctx context.Context, pubID string) (account *config.Account, errs []error) { - // Check BlacklistedAcctMap until we have deprecated it - if _, found := deps.cfg.BlacklistedAcctMap[pubID]; found { - return nil, []error{&errortypes.BlacklistedAcct{ - Message: fmt.Sprintf("Prebid-server has disabled Account ID: %s, please reach out to the prebid server host.", pubID), - }} - } - if deps.cfg.AccountRequired && pubID == pbsmetrics.PublisherUnknown { - return nil, []error{&errortypes.AcctRequired{ - Message: fmt.Sprintf("Prebid-server has been configured to discard requests without a valid Account ID. Please reach out to the prebid server host."), - }} - } - if accountJSON, accErrs := deps.accounts.FetchAccount(ctx, pubID); len(accErrs) > 0 || accountJSON == nil { - // pubID does not reference a valid account - if len(accErrs) > 0 { - errs = append(errs, errs...) - } - if deps.cfg.AccountRequired && deps.cfg.AccountDefaults.Disabled { - errs = append(errs, &errortypes.AcctRequired{ - Message: fmt.Sprintf("Prebid-server has been configured to discard requests without a valid Account ID. Please reach out to the prebid server host."), - }) - return nil, errs - } - // Make a copy of AccountDefaults instead of taking a reference, - // to preserve original pubID in case is needed to check NonStandardPublisherMap - pubAccount := deps.cfg.AccountDefaults - pubAccount.ID = pubID - account = &pubAccount - } else { - // pubID resolved to a valid account, merge with AccountDefaults for a complete config - account = &config.Account{} - completeJSON, err := jsonpatch.MergePatch(deps.cfg.AccountDefaultsJSON(), accountJSON) - if err == nil { - err = json.Unmarshal(completeJSON, account) - } - if err != nil { - errs = append(errs, err) - return nil, errs - } - // Fill in ID if needed, so it can be left out of account definition - if len(account.ID) == 0 { - account.ID = pubID - } - } - if account.Disabled { - errs = append(errs, &errortypes.BlacklistedAcct{ - Message: fmt.Sprintf("Prebid-server has disabled Account ID: %s, please reach out to the prebid server host.", pubID), - }) - return nil, errs - } - return -} diff --git a/endpoints/openrtb2/auction_test.go b/endpoints/openrtb2/auction_test.go index 7dc244a28c3..925cffcebeb 100644 --- a/endpoints/openrtb2/auction_test.go +++ b/endpoints/openrtb2/auction_test.go @@ -1984,8 +1984,7 @@ func (cf mockStoredReqFetcher) FetchRequests(ctx context.Context, requestIDs []s } var mockAccountData = map[string]json.RawMessage{ - "valid_acct": json.RawMessage(`{"disabled":false}`), - "disabled_acct": json.RawMessage(`{"disabled":true}`), + "valid_acct": json.RawMessage(`{"disabled":false}`), } type mockAccountFetcher struct { @@ -2058,70 +2057,3 @@ type hardcodedResponseIPValidator struct { func (v hardcodedResponseIPValidator) IsValid(net.IP, iputil.IPVersion) bool { return v.response } - -func TestGetAccount(t *testing.T) { - unknown := pbsmetrics.PublisherUnknown - testCases := []struct { - accountID string - // account_required - required bool - // account_defaults.disabled - disabled bool - // expected error, or nil if account should be found - err error - }{ - // Blacklisted account is always rejected even in permissive setup - {accountID: "bad_acct", required: false, disabled: false, err: &errortypes.BlacklistedAcct{}}, - - // empty pubID - {accountID: unknown, required: false, disabled: false, err: nil}, - {accountID: unknown, required: true, disabled: false, err: &errortypes.AcctRequired{}}, - {accountID: unknown, required: false, disabled: true, err: &errortypes.BlacklistedAcct{}}, - {accountID: unknown, required: true, disabled: true, err: &errortypes.AcctRequired{}}, - - // pubID given but is not a valid host account (does not exist) - {accountID: "doesnt_exist_acct", required: false, disabled: false, err: nil}, - {accountID: "doesnt_exist_acct", required: true, disabled: false, err: nil}, - {accountID: "doesnt_exist_acct", required: false, disabled: true, err: &errortypes.BlacklistedAcct{}}, - {accountID: "doesnt_exist_acct", required: true, disabled: true, err: &errortypes.AcctRequired{}}, - - // pubID given and matches a valid host account with Disabled: false - {accountID: "valid_acct", required: false, disabled: false, err: nil}, - {accountID: "valid_acct", required: true, disabled: false, err: nil}, - {accountID: "valid_acct", required: false, disabled: true, err: nil}, - {accountID: "valid_acct", required: true, disabled: true, err: nil}, - - // pubID given and matches a host account explicitly disabled (Disabled: true on account json) - {accountID: "disabled_acct", required: false, disabled: false, err: &errortypes.BlacklistedAcct{}}, - {accountID: "disabled_acct", required: true, disabled: false, err: &errortypes.BlacklistedAcct{}}, - {accountID: "disabled_acct", required: false, disabled: true, err: &errortypes.BlacklistedAcct{}}, - {accountID: "disabled_acct", required: true, disabled: true, err: &errortypes.BlacklistedAcct{}}, - } - - for _, test := range testCases { - description := fmt.Sprintf(`ID=%s/required=%t/disabled=%t`, test.accountID, test.required, test.disabled) - t.Run(description, func(t *testing.T) { - deps := &endpointDeps{ - cfg: &config.Configuration{ - BlacklistedAcctMap: map[string]bool{"bad_acct": true}, - AccountRequired: test.required, - AccountDefaults: config.Account{Disabled: test.disabled}, - }, - accounts: &mockAccountFetcher{}, - } - assert.NoError(t, deps.cfg.MarshalAccountDefaults()) - - account, errors := deps.getAccount(context.Background(), test.accountID) - - if test.err == nil { - assert.Empty(t, errors) - assert.Equal(t, test.accountID, account.ID, "account.ID must match requested ID") - assert.Equal(t, false, account.Disabled, "returned account must not be disabled") - } else { - assert.NotEmpty(t, errors, "expected errors but got success") - assert.Nil(t, account, "return account must be nil on error") - assert.IsType(t, test.err, errors[0], "error is of unexpected type") - } - }) - } -} diff --git a/endpoints/openrtb2/video_auction.go b/endpoints/openrtb2/video_auction.go index f5494751cc2..ab5634c7853 100644 --- a/endpoints/openrtb2/video_auction.go +++ b/endpoints/openrtb2/video_auction.go @@ -23,6 +23,7 @@ import ( "github.com/golang/glog" "github.com/julienschmidt/httprouter" "github.com/mxmCherry/openrtb" + accountService "github.com/prebid/prebid-server/account" "github.com/prebid/prebid-server/analytics" "github.com/prebid/prebid-server/config" "github.com/prebid/prebid-server/exchange" @@ -255,7 +256,7 @@ func (deps *endpointDeps) VideoAuctionEndpoint(w http.ResponseWriter, r *http.Re } // Look up account now that we have resolved the pubID value - account, acctIDErrs := deps.getAccount(ctx, labels.PubID) + account, acctIDErrs := accountService.GetAccount(ctx, deps.cfg, deps.accounts, labels.PubID) if len(acctIDErrs) > 0 { handleError(&labels, w, acctIDErrs, &vo, &debugLog) return diff --git a/exchange/adapter_map.go b/exchange/adapter_map.go index a160e87aad7..5bb788b63b9 100755 --- a/exchange/adapter_map.go +++ b/exchange/adapter_map.go @@ -31,6 +31,7 @@ import ( "github.com/prebid/prebid-server/adapters/beachfront" "github.com/prebid/prebid-server/adapters/beintoo" "github.com/prebid/prebid-server/adapters/brightroll" + "github.com/prebid/prebid-server/adapters/colossus" "github.com/prebid/prebid-server/adapters/consumable" "github.com/prebid/prebid-server/adapters/conversant" "github.com/prebid/prebid-server/adapters/cpmstar" @@ -118,6 +119,7 @@ func newAdapterMap(client *http.Client, cfg *config.Configuration, infos adapter openrtb_ext.BidderBeachfront: beachfront.NewBeachfrontBidder(cfg.Adapters[string(openrtb_ext.BidderBeachfront)].Endpoint, cfg.Adapters[string(openrtb_ext.BidderBeachfront)].ExtraAdapterInfo), openrtb_ext.BidderBeintoo: beintoo.NewBeintooBidder(cfg.Adapters[string(openrtb_ext.BidderBeintoo)].Endpoint), openrtb_ext.BidderBrightroll: brightroll.NewBrightrollBidder(cfg.Adapters[string(openrtb_ext.BidderBrightroll)].Endpoint, cfg.Adapters[string(openrtb_ext.BidderBrightroll)].ExtraAdapterInfo), + openrtb_ext.BidderColossus: colossus.NewColossusBidder(cfg.Adapters[string(openrtb_ext.BidderColossus)].Endpoint), openrtb_ext.BidderConsumable: consumable.NewConsumableBidder(cfg.Adapters[string(openrtb_ext.BidderConsumable)].Endpoint), openrtb_ext.BidderCpmstar: cpmstar.NewCpmstarBidder(cfg.Adapters[string(openrtb_ext.BidderCpmstar)].Endpoint), openrtb_ext.BidderDatablocks: datablocks.NewDatablocksBidder(cfg.Adapters[string(openrtb_ext.BidderDatablocks)].Endpoint), diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index 876eeab86bd..221f97c9697 100755 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -49,6 +49,7 @@ const ( BidderBeachfront BidderName = "beachfront" BidderBeintoo BidderName = "beintoo" BidderBrightroll BidderName = "brightroll" + BidderColossus BidderName = "colossus" BidderConsumable BidderName = "consumable" BidderConversant BidderName = "conversant" BidderCpmstar BidderName = "cpmstar" @@ -133,6 +134,7 @@ var BidderMap = map[string]BidderName{ "beachfront": BidderBeachfront, "beintoo": BidderBeintoo, "brightroll": BidderBrightroll, + "colossus": BidderColossus, "consumable": BidderConsumable, "conversant": BidderConversant, "cpmstar": BidderCpmstar, diff --git a/openrtb_ext/imp_colossus.go b/openrtb_ext/imp_colossus.go new file mode 100644 index 00000000000..8969000558d --- /dev/null +++ b/openrtb_ext/imp_colossus.go @@ -0,0 +1,6 @@ +package openrtb_ext + +// ExtImpColossus defines colossus specifiec param +type ExtImpColossus struct { + TagID string `json:"TagID"` +} diff --git a/static/bidder-info/colossus.yaml b/static/bidder-info/colossus.yaml new file mode 100644 index 00000000000..4d80661f887 --- /dev/null +++ b/static/bidder-info/colossus.yaml @@ -0,0 +1,12 @@ +maintainer: + email: "support@huddledmasses.com" +capabilities: + app: + mediaTypes: + - banner + - video + site: + mediaTypes: + - banner + - video + diff --git a/static/bidder-params/colossus.json b/static/bidder-params/colossus.json new file mode 100644 index 00000000000..10e7a9e3b38 --- /dev/null +++ b/static/bidder-params/colossus.json @@ -0,0 +1,15 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Colossus Adapter Params", + "description": "A schema which validates params accepted by the Colossus adapter", + + "type": "object", + "properties": { + "TagID": { + "type": "string", + "description": "An ID which identifies the colossus ad tag" + } + }, + "required" : [ "TagID" ] + } + \ No newline at end of file diff --git a/usersync/usersyncers/syncer.go b/usersync/usersyncers/syncer.go index 89540ea205b..c6ae984efc9 100755 --- a/usersync/usersyncers/syncer.go +++ b/usersync/usersyncers/syncer.go @@ -23,6 +23,7 @@ import ( "github.com/prebid/prebid-server/adapters/beachfront" "github.com/prebid/prebid-server/adapters/beintoo" "github.com/prebid/prebid-server/adapters/brightroll" + "github.com/prebid/prebid-server/adapters/colossus" "github.com/prebid/prebid-server/adapters/consumable" "github.com/prebid/prebid-server/adapters/conversant" "github.com/prebid/prebid-server/adapters/cpmstar" @@ -99,6 +100,7 @@ func NewSyncerMap(cfg *config.Configuration) map[openrtb_ext.BidderName]usersync insertIntoMap(cfg, syncers, openrtb_ext.BidderBeachfront, beachfront.NewBeachfrontSyncer) insertIntoMap(cfg, syncers, openrtb_ext.BidderBeintoo, beintoo.NewBeintooSyncer) insertIntoMap(cfg, syncers, openrtb_ext.BidderBrightroll, brightroll.NewBrightrollSyncer) + insertIntoMap(cfg, syncers, openrtb_ext.BidderColossus, colossus.NewColossusSyncer) insertIntoMap(cfg, syncers, openrtb_ext.BidderConsumable, consumable.NewConsumableSyncer) insertIntoMap(cfg, syncers, openrtb_ext.BidderConversant, conversant.NewConversantSyncer) insertIntoMap(cfg, syncers, openrtb_ext.BidderCpmstar, cpmstar.NewCpmstarSyncer) diff --git a/usersync/usersyncers/syncer_test.go b/usersync/usersyncers/syncer_test.go index 9197ed9507d..2cf0b2513c5 100755 --- a/usersync/usersyncers/syncer_test.go +++ b/usersync/usersyncers/syncer_test.go @@ -31,6 +31,7 @@ func TestNewSyncerMap(t *testing.T) { string(openrtb_ext.BidderBeachfront): syncConfig, string(openrtb_ext.BidderBeintoo): syncConfig, string(openrtb_ext.BidderBrightroll): syncConfig, + string(openrtb_ext.BidderColossus): syncConfig, string(openrtb_ext.BidderConsumable): syncConfig, string(openrtb_ext.BidderConversant): syncConfig, string(openrtb_ext.BidderCpmstar): syncConfig,