Skip to content
This repository was archived by the owner on Dec 22, 2022. It is now read-only.

Commit 25ea035

Browse files
authored
Add ValueImpression Adapter (prebid#1204)
1 parent cd2791a commit 25ea035

24 files changed

+994
-0
lines changed
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package valueimpression
2+
3+
import (
4+
"encoding/json"
5+
"testing"
6+
7+
"github.com/prebid/prebid-server/openrtb_ext"
8+
)
9+
10+
// This file actually intends to test static/bidder-params/valueimpression.json
11+
// These also validate the format of the external API: request.imp[i].ext.valueimpression
12+
// TestValidParams makes sure that the ValueImpression schema accepts all imp.ext fields which we intend to support.
13+
14+
func TestValidParams(t *testing.T) {
15+
validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params")
16+
if err != nil {
17+
t.Fatalf("Failed to fetch the json-schemas. %v", err)
18+
}
19+
20+
for _, validParam := range validParams {
21+
if err := validator.Validate(openrtb_ext.BidderValueImpression, json.RawMessage(validParam)); err != nil {
22+
t.Errorf("Schema rejected ValueImpression params: %s", validParam)
23+
}
24+
}
25+
}
26+
27+
// TestInvalidParams makes sure that the ValueImpression schema rejects all the imp.ext fields we don't support.
28+
func TestInvalidParams(t *testing.T) {
29+
validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params")
30+
if err != nil {
31+
t.Fatalf("Failed to fetch the json-schemas. %v", err)
32+
}
33+
34+
for _, invalidParam := range invalidParams {
35+
if err := validator.Validate(openrtb_ext.BidderValueImpression, json.RawMessage(invalidParam)); err == nil {
36+
t.Errorf("Schema allowed unexpected params: %s", invalidParam)
37+
}
38+
}
39+
}
40+
41+
var validParams = []string{
42+
`{"siteId": "123"}`,
43+
}
44+
45+
var invalidParams = []string{
46+
`{}`,
47+
`null`,
48+
`true`,
49+
`154`,
50+
`{"siteId": 123}`, // siteId should be string
51+
`{"invalid_param": "123"}`,
52+
}

adapters/valueimpression/usersync.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package valueimpression
2+
3+
import (
4+
"text/template"
5+
6+
"github.com/prebid/prebid-server/adapters"
7+
"github.com/prebid/prebid-server/usersync"
8+
)
9+
10+
func NewValueImpressionSyncer(temp *template.Template) usersync.Usersyncer {
11+
return adapters.NewSyncer("valueimpression", 0, temp, adapters.SyncTypeRedirect)
12+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package valueimpression
2+
3+
import (
4+
"testing"
5+
"text/template"
6+
7+
"github.com/prebid/prebid-server/privacy"
8+
"github.com/prebid/prebid-server/privacy/ccpa"
9+
"github.com/prebid/prebid-server/privacy/gdpr"
10+
"github.com/stretchr/testify/assert"
11+
)
12+
13+
func TestValueImpressionSyncer(t *testing.T) {
14+
syncURL := "https://rtb.valueimpression.com/usersync?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&redirectUri=http%3A%2F%2Flocalhost:8000%2Fsetuid%3Fbidder%3Dvalueimpression%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24UID"
15+
syncURLTemplate := template.Must(
16+
template.New("sync-template").Parse(syncURL),
17+
)
18+
19+
syncer := NewValueImpressionSyncer(syncURLTemplate)
20+
syncInfo, err := syncer.GetUsersyncInfo(privacy.Policies{
21+
GDPR: gdpr.Policy{
22+
Signal: "1",
23+
Consent: "BOPVK28OVJoTBABABAENBs-AAAAhuAKAANAAoACwAGgAPAAxAB0AHgAQAAiABOADkA",
24+
},
25+
CCPA: ccpa.Policy{
26+
Value: "1NYN",
27+
},
28+
})
29+
30+
assert.NoError(t, err)
31+
assert.Equal(t, "https://rtb.valueimpression.com/usersync?gdpr=1&gdpr_consent=BOPVK28OVJoTBABABAENBs-AAAAhuAKAANAAoACwAGgAPAAxAB0AHgAQAAiABOADkA&redirectUri=http%3A%2F%2Flocalhost:8000%2Fsetuid%3Fbidder%3Dvalueimpression%26gdpr%3D1%26gdpr_consent%3DBOPVK28OVJoTBABABAENBs-AAAAhuAKAANAAoACwAGgAPAAxAB0AHgAQAAiABOADkA%26uid%3D%24UID", syncInfo.URL)
32+
assert.Equal(t, "redirect", syncInfo.Type)
33+
assert.EqualValues(t, 0, syncer.GDPRVendorID())
34+
assert.False(t, syncInfo.SupportCORS)
35+
}
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
package valueimpression
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"net/http"
7+
8+
"github.com/mxmCherry/openrtb"
9+
"github.com/prebid/prebid-server/adapters"
10+
"github.com/prebid/prebid-server/errortypes"
11+
"github.com/prebid/prebid-server/openrtb_ext"
12+
)
13+
14+
type ValueImpressionAdapter struct {
15+
endpoint string
16+
}
17+
18+
func (a *ValueImpressionAdapter) MakeRequests(request *openrtb.BidRequest, unused *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
19+
var errs []error
20+
var adapterRequests []*adapters.RequestData
21+
22+
if err := preprocess(request); err != nil {
23+
errs = append(errs, err)
24+
return nil, errs
25+
}
26+
27+
adapterReq, err := a.makeRequest(request)
28+
if err != nil {
29+
errs = append(errs, err)
30+
return nil, errs
31+
}
32+
33+
adapterRequests = append(adapterRequests, adapterReq)
34+
35+
return adapterRequests, errs
36+
}
37+
38+
func (a *ValueImpressionAdapter) makeRequest(request *openrtb.BidRequest) (*adapters.RequestData, error) {
39+
var err error
40+
41+
jsonBody, err := json.Marshal(request)
42+
if err != nil {
43+
return nil, err
44+
}
45+
46+
headers := http.Header{}
47+
headers.Add("Content-Type", "application/json;charset=utf-8")
48+
49+
return &adapters.RequestData{
50+
Method: "POST",
51+
Uri: a.endpoint,
52+
Body: jsonBody,
53+
Headers: headers,
54+
}, nil
55+
}
56+
57+
func preprocess(request *openrtb.BidRequest) error {
58+
if len(request.Imp) == 0 {
59+
return &errortypes.BadInput{
60+
Message: "No Imps in Bid Request",
61+
}
62+
}
63+
for i := 0; i < len(request.Imp); i++ {
64+
var imp = &request.Imp[i]
65+
var bidderExt adapters.ExtImpBidder
66+
67+
if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil {
68+
return &errortypes.BadInput{
69+
Message: err.Error(),
70+
}
71+
}
72+
73+
var extImp openrtb_ext.ExtImpValueImpression
74+
if err := json.Unmarshal(bidderExt.Bidder, &extImp); err != nil {
75+
return &errortypes.BadInput{
76+
Message: err.Error(),
77+
}
78+
}
79+
80+
imp.Ext = bidderExt.Bidder
81+
}
82+
83+
return nil
84+
}
85+
86+
// MakeBids based on valueimpression server response
87+
func (a *ValueImpressionAdapter) MakeBids(bidRequest *openrtb.BidRequest, unused *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) {
88+
if responseData.StatusCode == http.StatusNoContent {
89+
return nil, nil
90+
}
91+
92+
if responseData.StatusCode == http.StatusBadRequest {
93+
return nil, []error{&errortypes.BadInput{
94+
Message: fmt.Sprintf("Bad user input: HTTP status %d", responseData.StatusCode),
95+
}}
96+
}
97+
98+
if responseData.StatusCode != http.StatusOK {
99+
return nil, []error{&errortypes.BadServerResponse{
100+
Message: fmt.Sprintf("Bad server response: HTTP status %d", responseData.StatusCode),
101+
}}
102+
}
103+
104+
var bidResponse openrtb.BidResponse
105+
106+
if err := json.Unmarshal(responseData.Body, &bidResponse); err != nil {
107+
return nil, []error{&errortypes.BadServerResponse{
108+
Message: err.Error(),
109+
}}
110+
}
111+
112+
if len(bidResponse.SeatBid) == 0 {
113+
return nil, nil
114+
}
115+
116+
rv := adapters.NewBidderResponseWithBidsCapacity(len(bidResponse.SeatBid[0].Bid))
117+
var errors []error
118+
119+
for _, seatbid := range bidResponse.SeatBid {
120+
for _, bid := range seatbid.Bid {
121+
foundMatchingBid := false
122+
bidType := openrtb_ext.BidTypeBanner
123+
for _, imp := range bidRequest.Imp {
124+
if imp.ID == bid.ImpID {
125+
foundMatchingBid = true
126+
if imp.Banner != nil {
127+
bidType = openrtb_ext.BidTypeBanner
128+
} else if imp.Video != nil {
129+
bidType = openrtb_ext.BidTypeVideo
130+
}
131+
break
132+
}
133+
}
134+
135+
if foundMatchingBid {
136+
rv.Bids = append(rv.Bids, &adapters.TypedBid{
137+
Bid: &bid,
138+
BidType: bidType,
139+
})
140+
} else {
141+
errors = append(errors, &errortypes.BadServerResponse{
142+
Message: fmt.Sprintf("bid id='%s' could not find valid impid='%s'", bid.ID, bid.ImpID),
143+
})
144+
}
145+
}
146+
}
147+
return rv, errors
148+
}
149+
150+
func NewValueImpressionBidder(endpoint string) *ValueImpressionAdapter {
151+
return &ValueImpressionAdapter{
152+
endpoint: endpoint,
153+
}
154+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package valueimpression
2+
3+
import (
4+
"testing"
5+
6+
"github.com/prebid/prebid-server/adapters/adapterstest"
7+
)
8+
9+
func TestJsonSamples(t *testing.T) {
10+
adapterstest.RunJSONBidderTest(t, "valueimpressiontest", NewValueImpressionBidder("//host"))
11+
}

0 commit comments

Comments
 (0)