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,