diff --git a/adapters/adman/adman.go b/adapters/adman/adman.go
new file mode 100644
index 00000000000..aa8d0dc6e74
--- /dev/null
+++ b/adapters/adman/adman.go
@@ -0,0 +1,140 @@
+package adman
+
+import (
+ "encoding/json"
+ "fmt"
+ "net/http"
+
+ "github.com/mxmCherry/openrtb"
+ "github.com/prebid/prebid-server/adapters"
+ "github.com/prebid/prebid-server/errortypes"
+ "github.com/prebid/prebid-server/openrtb_ext"
+)
+
+// AdmanAdapter struct
+type AdmanAdapter struct {
+ URI string
+}
+
+// NewAdmanBidder Initializes the Bidder
+func NewAdmanBidder(endpoint string) *AdmanAdapter {
+ return &AdmanAdapter{
+ URI: endpoint,
+ }
+}
+
+type admanParams struct {
+ TagID string `json:"TagID"`
+}
+
+// MakeRequests create bid request for adman demand
+func (a *AdmanAdapter) MakeRequests(request *openrtb.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
+ var errs []error
+ var admanExt openrtb_ext.ExtImpAdman
+ var err error
+
+ var adapterRequests []*adapters.RequestData
+
+ reqCopy := *request
+ for _, imp := range request.Imp {
+ reqCopy.Imp = []openrtb.Imp{imp}
+
+ var bidderExt adapters.ExtImpBidder
+ if err = json.Unmarshal(reqCopy.Imp[0].Ext, &bidderExt); err != nil {
+ errs = append(errs, err)
+ continue
+ }
+
+ if err = json.Unmarshal(bidderExt.Bidder, &admanExt); err != nil {
+ errs = append(errs, err)
+ continue
+ }
+
+ reqCopy.Imp[0].TagID = admanExt.TagID
+
+ adapterReq, errors := a.makeRequest(&reqCopy)
+ if adapterReq != nil {
+ adapterRequests = append(adapterRequests, adapterReq)
+ }
+ errs = append(errs, errors...)
+ }
+ return adapterRequests, errs
+}
+
+func (a *AdmanAdapter) 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 *AdmanAdapter) 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),
+ }}
+ }
+
+ 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/adman/adman_test.go b/adapters/adman/adman_test.go
new file mode 100644
index 00000000000..da0f37e9a48
--- /dev/null
+++ b/adapters/adman/adman_test.go
@@ -0,0 +1,12 @@
+package adman
+
+import (
+ "testing"
+
+ "github.com/prebid/prebid-server/adapters/adapterstest"
+)
+
+func TestJsonSamples(t *testing.T) {
+ admanAdapter := NewAdmanBidder("http://eu-ams-1.admanmedia.com/?c=o&m=ortb")
+ adapterstest.RunJSONBidderTest(t, "admantest", admanAdapter)
+}
diff --git a/adapters/adman/admantest/exemplary/simple-banner.json b/adapters/adman/admantest/exemplary/simple-banner.json
new file mode 100644
index 00000000000..41f76e00645
--- /dev/null
+++ b/adapters/adman/admantest/exemplary/simple-banner.json
@@ -0,0 +1,134 @@
+{
+ "mockBidRequest": {
+ "id": "test-request-id",
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "banner": {
+ "format": [
+ {
+ "w": 300,
+ "h": 250
+ },
+ {
+ "w": 300,
+ "h": 600
+ }
+ ]
+ },
+ "tagid": "16",
+ "ext": {
+ "bidder": {
+ "TagID": "16"
+ }
+ }
+ }
+ ],
+ "app": {
+ "id": "1",
+ "bundle": "com.wls.testwlsapplication"
+ },
+ "device": {
+ "ip": "123.123.123.123",
+ "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
+ }
+},
+
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "uri": "http://eu-ams-1.admanmedia.com/?c=o&m=ortb",
+ "body": {
+ "id": "test-request-id",
+ "imp": [
+ {
+ "id": "test-imp-id",
+ "banner": {
+ "format": [
+ {
+ "w": 300,
+ "h": 250
+ },
+ {
+ "w": 300,
+ "h": 600
+ }
+ ]
+ },
+ "tagid": "16",
+ "ext": {
+ "bidder": {
+ "TagID": "16"
+ }
+ }
+ }
+ ],
+ "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"
+ }
+ }
+ }
+ ],
+ "seat": "adman"
+ }
+ ],
+ "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": 300,
+ "h": 250,
+ "ext": {
+ "prebid": {
+ "type": "banner"
+ }
+ }
+ },
+ "type": "banner"
+ }
+ ]
+ }
+ ]
+}
diff --git a/adapters/adman/admantest/exemplary/simple-video.json b/adapters/adman/admantest/exemplary/simple-video.json
new file mode 100644
index 00000000000..d7fa82d274d
--- /dev/null
+++ b/adapters/adman/admantest/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": "22"
+ }
+ }
+ }
+ ]
+ },
+
+ "httpCalls": [
+ {
+ "expectedRequest": {
+ "uri": "http://eu-ams-1.admanmedia.com/?c=o&m=ortb",
+ "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": "22",
+ "ext": {
+ "bidder": {
+ "TagID": "22"
+ }
+ }
+ }
+ ]
+ }
+ },
+ "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": "adman"
+ }
+ ],
+ "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/adman/admantest/exemplary/simple-web-banner.json b/adapters/adman/admantest/exemplary/simple-web-banner.json
new file mode 100644
index 00000000000..ce872bff52b
--- /dev/null
+++ b/adapters/adman/admantest/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://eu-ams-1.admanmedia.com/?c=o&m=ortb",
+ "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": "adman"
+ }
+ ],
+ "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/adman/admantest/params/banner.json b/adapters/adman/admantest/params/banner.json
new file mode 100644
index 00000000000..03fa8f3f2d8
--- /dev/null
+++ b/adapters/adman/admantest/params/banner.json
@@ -0,0 +1,3 @@
+{
+ "TagID": "16"
+}
\ No newline at end of file
diff --git a/adapters/adman/admantest/params/race/banner.json b/adapters/adman/admantest/params/race/banner.json
new file mode 100644
index 00000000000..03fa8f3f2d8
--- /dev/null
+++ b/adapters/adman/admantest/params/race/banner.json
@@ -0,0 +1,3 @@
+{
+ "TagID": "16"
+}
\ No newline at end of file
diff --git a/adapters/adman/admantest/params/race/video.json b/adapters/adman/admantest/params/race/video.json
new file mode 100644
index 00000000000..e776c928a7e
--- /dev/null
+++ b/adapters/adman/admantest/params/race/video.json
@@ -0,0 +1,3 @@
+{
+ "TagID": "22"
+}
\ No newline at end of file
diff --git a/adapters/adman/admantest/params/video.json b/adapters/adman/admantest/params/video.json
new file mode 100644
index 00000000000..e776c928a7e
--- /dev/null
+++ b/adapters/adman/admantest/params/video.json
@@ -0,0 +1,3 @@
+{
+ "TagID": "22"
+}
\ No newline at end of file
diff --git a/adapters/adman/admantest/supplemental/bad-imp-ext.json b/adapters/adman/admantest/supplemental/bad-imp-ext.json
new file mode 100644
index 00000000000..db3c8de5767
--- /dev/null
+++ b/adapters/adman/admantest/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": "16",
+ "ext": {
+ "adman": {
+ "TagID": "16"
+ }
+ }
+ }
+ ],
+ "app": {
+ "id": "1",
+ "bundle": "com.wls.testwlsapplication"
+ },
+ "device": {
+ "ip": "123.123.123.123",
+ "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
+ }
+},
+"expectedMakeRequestsErrors": [
+ {
+ "value": "unexpected end of JSON input",
+ "comparison": "literal"
+ }
+]
+}
diff --git a/adapters/adman/admantest/supplemental/bad_response.json b/adapters/adman/admantest/supplemental/bad_response.json
new file mode 100644
index 00000000000..8c349297e73
--- /dev/null
+++ b/adapters/adman/admantest/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://eu-ams-1.admanmedia.com/?c=o&m=ortb",
+ "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/adman/admantest/supplemental/no-imp-ext-1.json b/adapters/adman/admantest/supplemental/no-imp-ext-1.json
new file mode 100644
index 00000000000..8fad5ba5ef0
--- /dev/null
+++ b/adapters/adman/admantest/supplemental/no-imp-ext-1.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": "16",
+ "ext": ""
+ }
+ ],
+ "app": {
+ "id": "1",
+ "bundle": "com.wls.testwlsapplication"
+ },
+ "device": {
+ "ip": "123.123.123.123",
+ "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
+ }
+ },
+ "expectedMakeRequestsErrors": [
+ {
+ "value": "json: cannot unmarshal string into Go value of type adapters.ExtImpBidder",
+ "comparison": "literal"
+ }
+ ]
+ }
+
\ No newline at end of file
diff --git a/adapters/adman/admantest/supplemental/no-imp-ext-2.json b/adapters/adman/admantest/supplemental/no-imp-ext-2.json
new file mode 100644
index 00000000000..337dfd044b3
--- /dev/null
+++ b/adapters/adman/admantest/supplemental/no-imp-ext-2.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": "16",
+ "ext": {}
+ }
+ ],
+ "app": {
+ "id": "1",
+ "bundle": "com.wls.testwlsapplication"
+ },
+ "device": {
+ "ip": "123.123.123.123",
+ "ifa": "zxcjbzxmc-zxcbmz-zxbcz-zxczx"
+ }
+ },
+ "expectedMakeRequestsErrors": [
+ {
+ "value": "unexpected end of JSON input",
+ "comparison": "literal"
+ }
+ ]
+ }
+
\ No newline at end of file
diff --git a/adapters/adman/admantest/supplemental/status-204.json b/adapters/adman/admantest/supplemental/status-204.json
new file mode 100644
index 00000000000..7f9a12dec29
--- /dev/null
+++ b/adapters/adman/admantest/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://eu-ams-1.admanmedia.com/?c=o&m=ortb",
+ "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/adman/admantest/supplemental/status-404.json b/adapters/adman/admantest/supplemental/status-404.json
new file mode 100644
index 00000000000..560878342f0
--- /dev/null
+++ b/adapters/adman/admantest/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://eu-ams-1.admanmedia.com/?c=o&m=ortb",
+ "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/adman/params_test.go b/adapters/adman/params_test.go
new file mode 100644
index 00000000000..a80c2a44b8b
--- /dev/null
+++ b/adapters/adman/params_test.go
@@ -0,0 +1,46 @@
+package adman
+
+import (
+ "encoding/json"
+ "testing"
+
+ "github.com/prebid/prebid-server/openrtb_ext"
+)
+
+// TestValidParams makes sure that the adman 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.BidderAdman, json.RawMessage(validParam)); err != nil {
+ t.Errorf("Schema rejected adman params: %s", validParam)
+ }
+ }
+}
+
+// TestInvalidParams makes sure that the adman 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.BidderAdman, json.RawMessage(invalidParam)); err == nil {
+ t.Errorf("Schema allowed unexpected params: %s", invalidParam)
+ }
+ }
+}
+
+var validParams = []string{
+ `{"TagID": "16"}`,
+}
+
+var invalidParams = []string{
+ `{"id": "123"}`,
+ `{"tagid": "123"}`,
+ `{"TagID": 16}`,
+}
diff --git a/adapters/adman/usersync.go b/adapters/adman/usersync.go
new file mode 100644
index 00000000000..aae6afcdfcd
--- /dev/null
+++ b/adapters/adman/usersync.go
@@ -0,0 +1,13 @@
+package adman
+
+import (
+ "text/template"
+
+ "github.com/prebid/prebid-server/adapters"
+ "github.com/prebid/prebid-server/usersync"
+)
+
+// NewAdmanSyncer returns adman syncer
+func NewAdmanSyncer(temp *template.Template) usersync.Usersyncer {
+ return adapters.NewSyncer("adman", 149, temp, adapters.SyncTypeRedirect)
+}
diff --git a/adapters/adman/usersync_test.go b/adapters/adman/usersync_test.go
new file mode 100644
index 00000000000..55a6e2cec97
--- /dev/null
+++ b/adapters/adman/usersync_test.go
@@ -0,0 +1,35 @@
+package adman
+
+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 TestAdmanSyncer(t *testing.T) {
+ syncURL := "https://sync.admanmedia.com/pbs.gif?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redir=http%3A%2F%2Flocalhost%3A8000%2Fsetuid%3Fbidder%3Dadman%26uid%3D%5BUID%5D"
+ syncURLTemplate := template.Must(
+ template.New("sync-template").Parse(syncURL),
+ )
+
+ syncer := NewAdmanSyncer(syncURLTemplate)
+ syncInfo, err := syncer.GetUsersyncInfo(privacy.Policies{
+ GDPR: gdpr.Policy{
+ Signal: "0",
+ Consent: "ANDFJDS",
+ },
+ CCPA: ccpa.Policy{
+ Value: "1-YY",
+ },
+ })
+
+ assert.NoError(t, err)
+ assert.Equal(t, "https://sync.admanmedia.com/pbs.gif?gdpr=0&gdpr_consent=ANDFJDS&us_privacy=1-YY&redir=http%3A%2F%2Flocalhost%3A8000%2Fsetuid%3Fbidder%3Dadman%26uid%3D%5BUID%5D", syncInfo.URL)
+ assert.Equal(t, "redirect", syncInfo.Type)
+ assert.EqualValues(t, 149, syncer.GDPRVendorID())
+ assert.Equal(t, false, syncInfo.SupportCORS)
+}
diff --git a/config/config.go b/config/config.go
index c50118e2008..bb2c3191491 100755
--- a/config/config.go
+++ b/config/config.go
@@ -563,6 +563,7 @@ func (cfg *Configuration) setDerivedDefaults() {
setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderAdtarget, "https://sync.console.adtarget.com.tr/csync?t=p&ep=0&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redir="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dadtarget%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%7Buid%7D")
setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderAdtelligent, "https://sync.adtelligent.com/csync?t=p&ep=0&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redir="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dadtelligent%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%7Buid%7D")
setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderAdmixer, "https://inv-nets.admixer.net/adxcm.aspx?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redir=1&rurl="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dadmixer%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24%24visitor_cookie%24%24")
+ setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderAdman, "https://sync.admanmedia.com/pbs.gif?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redir="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dadman%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%5BUID%5D")
// openrtb_ext.BidderAdOcean doesn't have a good default.
setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderAdvangelists, "https://nep.advangelists.com/xp/user-sync?acctid={aid}&&redirect="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dadvangelists%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24UID")
setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderAJA, "https://ad.as.amanad.adtdp.com/v1/sync/ssp?ssp=4&gdpr={{.GDPR}}&us_privacy={{.USPrivacy}}&redir="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Daja%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%25s")
@@ -763,6 +764,7 @@ func SetupViper(v *viper.Viper, filename string) {
v.SetDefault("adapters.adhese.endpoint", "https://ads-{{.AccountID}}.adhese.com/json")
v.SetDefault("adapters.adkernel.endpoint", "http://{{.Host}}/hb?zone={{.ZoneID}}")
v.SetDefault("adapters.adkerneladn.endpoint", "http://{{.Host}}/rtbpub?account={{.PublisherID}}")
+ v.SetDefault("adapters.adman.endpoint", "http://eu-ams-1.admanmedia.com/?c=o&m=ortb")
v.SetDefault("adapters.admixer.endpoint", "http://inv-nets.admixer.net/pbs.aspx")
v.SetDefault("adapters.adocean.endpoint", "https://{{.Host}}")
v.SetDefault("adapters.adoppler.endpoint", "http://app.trustedmarketplace.io/ads")
diff --git a/exchange/adapter_map.go b/exchange/adapter_map.go
index 44054df06fd..c30bb0c622e 100755
--- a/exchange/adapter_map.go
+++ b/exchange/adapter_map.go
@@ -14,6 +14,7 @@ import (
"github.com/prebid/prebid-server/adapters/adhese"
"github.com/prebid/prebid-server/adapters/adkernel"
"github.com/prebid/prebid-server/adapters/adkernelAdn"
+ "github.com/prebid/prebid-server/adapters/adman"
"github.com/prebid/prebid-server/adapters/admixer"
"github.com/prebid/prebid-server/adapters/adocean"
"github.com/prebid/prebid-server/adapters/adoppler"
@@ -98,6 +99,7 @@ func newAdapterMap(client *http.Client, cfg *config.Configuration, infos adapter
openrtb_ext.BidderAdhese: adhese.NewAdheseBidder(cfg.Adapters[string(openrtb_ext.BidderAdhese)].Endpoint),
openrtb_ext.BidderAdkernel: adkernel.NewAdkernelAdapter(cfg.Adapters[strings.ToLower(string(openrtb_ext.BidderAdkernel))].Endpoint),
openrtb_ext.BidderAdkernelAdn: adkernelAdn.NewAdkernelAdnAdapter(cfg.Adapters[strings.ToLower(string(openrtb_ext.BidderAdkernelAdn))].Endpoint),
+ openrtb_ext.BidderAdman: adman.NewAdmanBidder(cfg.Adapters[string(openrtb_ext.BidderAdman)].Endpoint),
openrtb_ext.BidderAdmixer: admixer.NewAdmixerBidder(cfg.Adapters[strings.ToLower(string(openrtb_ext.BidderAdmixer))].Endpoint),
openrtb_ext.BidderAdOcean: adocean.NewAdOceanBidder(client, cfg.Adapters[strings.ToLower(string(openrtb_ext.BidderAdOcean))].Endpoint),
openrtb_ext.BidderAdoppler: adoppler.NewAdopplerBidder(cfg.Adapters[string(openrtb_ext.BidderAdoppler)].Endpoint),
diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go
index 1f9cffb9938..49d7b09d671 100755
--- a/openrtb_ext/bidders.go
+++ b/openrtb_ext/bidders.go
@@ -31,6 +31,7 @@ const (
BidderAdkernel BidderName = "adkernel"
BidderAdkernelAdn BidderName = "adkernelAdn"
BidderAdpone BidderName = "adpone"
+ BidderAdman BidderName = "adman"
BidderAdmixer BidderName = "admixer"
BidderAdOcean BidderName = "adocean"
BidderAdtarget BidderName = "adtarget"
@@ -110,6 +111,7 @@ var BidderMap = map[string]BidderName{
"adhese": BidderAdhese,
"adkernel": BidderAdkernel,
"adkernelAdn": BidderAdkernelAdn,
+ "adman": BidderAdman,
"admixer": BidderAdmixer,
"adocean": BidderAdOcean,
"adpone": BidderAdpone,
diff --git a/openrtb_ext/imp_adman.go b/openrtb_ext/imp_adman.go
new file mode 100644
index 00000000000..bc79415452c
--- /dev/null
+++ b/openrtb_ext/imp_adman.go
@@ -0,0 +1,6 @@
+package openrtb_ext
+
+// ExtImpAdman defines adman specifiec param
+type ExtImpAdman struct {
+ TagID string `json:"TagID"`
+}
diff --git a/static/bidder-info/adman.yaml b/static/bidder-info/adman.yaml
new file mode 100644
index 00000000000..932ef2e4242
--- /dev/null
+++ b/static/bidder-info/adman.yaml
@@ -0,0 +1,11 @@
+maintainer:
+ email: "prebid@admanmedia.com"
+capabilities:
+ app:
+ mediaTypes:
+ - banner
+ - video
+ site:
+ mediaTypes:
+ - banner
+ - video
\ No newline at end of file
diff --git a/static/bidder-params/adman.json b/static/bidder-params/adman.json
new file mode 100644
index 00000000000..90021e2cdfd
--- /dev/null
+++ b/static/bidder-params/adman.json
@@ -0,0 +1,15 @@
+{
+ "$schema": "http://json-schema.org/draft-04/schema#",
+ "title": "Adman Adapter Params",
+ "description": "A schema which validates params accepted by the Adman adapter",
+
+ "type": "object",
+ "properties": {
+ "TagID": {
+ "type": "string",
+ "description": "An ID which identifies the adman ad tag"
+ }
+ },
+ "required" : [ "TagID" ]
+ }
+
\ No newline at end of file
diff --git a/usersync/usersyncers/syncer.go b/usersync/usersyncers/syncer.go
index 5657c8b7010..f1f643afb74 100755
--- a/usersync/usersyncers/syncer.go
+++ b/usersync/usersyncers/syncer.go
@@ -9,6 +9,7 @@ import (
"github.com/prebid/prebid-server/adapters/adform"
"github.com/prebid/prebid-server/adapters/adkernel"
"github.com/prebid/prebid-server/adapters/adkernelAdn"
+ "github.com/prebid/prebid-server/adapters/adman"
"github.com/prebid/prebid-server/adapters/admixer"
"github.com/prebid/prebid-server/adapters/adocean"
"github.com/prebid/prebid-server/adapters/adpone"
@@ -84,6 +85,7 @@ func NewSyncerMap(cfg *config.Configuration) map[openrtb_ext.BidderName]usersync
insertIntoMap(cfg, syncers, openrtb_ext.BidderAdform, adform.NewAdformSyncer)
insertIntoMap(cfg, syncers, openrtb_ext.BidderAdkernel, adkernel.NewAdkernelSyncer)
insertIntoMap(cfg, syncers, openrtb_ext.BidderAdkernelAdn, adkernelAdn.NewAdkernelAdnSyncer)
+ insertIntoMap(cfg, syncers, openrtb_ext.BidderAdman, adman.NewAdmanSyncer)
insertIntoMap(cfg, syncers, openrtb_ext.BidderAdmixer, admixer.NewAdmixerSyncer)
insertIntoMap(cfg, syncers, openrtb_ext.BidderAdOcean, adocean.NewAdOceanSyncer)
insertIntoMap(cfg, syncers, openrtb_ext.BidderAdpone, adpone.NewadponeSyncer)
diff --git a/usersync/usersyncers/syncer_test.go b/usersync/usersyncers/syncer_test.go
index 363cd491648..b23541eaf8a 100755
--- a/usersync/usersyncers/syncer_test.go
+++ b/usersync/usersyncers/syncer_test.go
@@ -18,6 +18,7 @@ func TestNewSyncerMap(t *testing.T) {
string(openrtb_ext.BidderAdform): syncConfig,
string(openrtb_ext.BidderAdkernel): syncConfig,
string(openrtb_ext.BidderAdkernelAdn): syncConfig,
+ string(openrtb_ext.BidderAdman): syncConfig,
string(openrtb_ext.BidderAdmixer): syncConfig,
string(openrtb_ext.BidderAdOcean): syncConfig,
string(openrtb_ext.BidderAdpone): syncConfig,