Skip to content

Commit 1e9ecd4

Browse files
KushnerykPavelKushneryk PavloSmartyAdsSSP
authored
Smarty ads adapter (prebid#1500)
Co-authored-by: Kushneryk Pavlo <[email protected]> Co-authored-by: user <[email protected]>
1 parent 2d03b85 commit 1e9ecd4

29 files changed

+1953
-0
lines changed

adapters/smartyads/params_test.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package smartyads
2+
3+
import (
4+
"encoding/json"
5+
"testing"
6+
7+
"github.com/prebid/prebid-server/openrtb_ext"
8+
)
9+
10+
var validParams = []string{
11+
`{ "host": "ep1", "sourceid": "partner", "accountid": "hash" }`,
12+
}
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.BidderSmartyAds, json.RawMessage(validParam)); err != nil {
22+
t.Errorf("Schema rejected SmartyAds params: %s", validParam)
23+
}
24+
}
25+
}
26+
27+
var invalidParams = []string{
28+
``,
29+
`null`,
30+
`true`,
31+
`5`,
32+
`4.2`,
33+
`[]`,
34+
`{}`,
35+
`{"adCode": "string", "seatCode": 5, "originalPublisherid": "string"}`,
36+
`{ "host": "ep1", "sourceid": "partner" }`,
37+
`{ "host": "ep1, "accountid": "hash" }`,
38+
`{ "sourceid": "partner", "sourceid": "partner" }`,
39+
}
40+
41+
func TestInvalidParams(t *testing.T) {
42+
validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params")
43+
if err != nil {
44+
t.Fatalf("Failed to fetch the json-schemas. %v", err)
45+
}
46+
47+
for _, invalidParam := range invalidParams {
48+
if err := validator.Validate(openrtb_ext.BidderSmartyAds, json.RawMessage(invalidParam)); err == nil {
49+
t.Errorf("Schema allowed unexpected params: %s", invalidParam)
50+
}
51+
}
52+
}

adapters/smartyads/smartyads.go

Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
package smartyads
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"net/http"
7+
"strconv"
8+
"text/template"
9+
10+
"github.com/mxmCherry/openrtb"
11+
"github.com/prebid/prebid-server/adapters"
12+
"github.com/prebid/prebid-server/errortypes"
13+
"github.com/prebid/prebid-server/macros"
14+
"github.com/prebid/prebid-server/openrtb_ext"
15+
)
16+
17+
type SmartyAdsAdapter struct {
18+
endpoint template.Template
19+
}
20+
21+
func NewSmartyAdsBidder(endpointTemplate string) *SmartyAdsAdapter {
22+
template, err := template.New("endpointTemplate").Parse(endpointTemplate)
23+
if err != nil {
24+
return nil
25+
}
26+
return &SmartyAdsAdapter{endpoint: *template}
27+
}
28+
29+
func GetHeaders(request *openrtb.BidRequest) *http.Header {
30+
headers := http.Header{}
31+
headers.Add("Content-Type", "application/json;charset=utf-8")
32+
headers.Add("Accept", "application/json")
33+
headers.Add("X-Openrtb-Version", "2.5")
34+
35+
if request.Device != nil {
36+
if len(request.Device.UA) > 0 {
37+
headers.Add("User-Agent", request.Device.UA)
38+
}
39+
40+
if len(request.Device.IPv6) > 0 {
41+
headers.Add("X-Forwarded-For", request.Device.IPv6)
42+
}
43+
44+
if len(request.Device.IP) > 0 {
45+
headers.Add("X-Forwarded-For", request.Device.IP)
46+
}
47+
48+
if len(request.Device.Language) > 0 {
49+
headers.Add("Accept-Language", request.Device.Language)
50+
}
51+
52+
if request.Device.DNT != nil {
53+
headers.Add("Dnt", strconv.Itoa(int(*request.Device.DNT)))
54+
}
55+
}
56+
57+
return &headers
58+
}
59+
60+
func (a *SmartyAdsAdapter) MakeRequests(
61+
openRTBRequest *openrtb.BidRequest,
62+
reqInfo *adapters.ExtraRequestInfo,
63+
) (
64+
requestsToBidder []*adapters.RequestData,
65+
errs []error,
66+
) {
67+
68+
var errors []error
69+
var smartyadsExt *openrtb_ext.ExtSmartyAds
70+
var err error
71+
72+
for i, imp := range openRTBRequest.Imp {
73+
smartyadsExt, err = a.getImpressionExt(&imp)
74+
if err != nil {
75+
errors = append(errors, err)
76+
break
77+
}
78+
openRTBRequest.Imp[i].Ext = nil
79+
}
80+
81+
if len(errors) > 0 {
82+
return nil, errors
83+
}
84+
85+
url, err := a.buildEndpointURL(smartyadsExt)
86+
if err != nil {
87+
return nil, []error{err}
88+
}
89+
90+
reqJSON, err := json.Marshal(openRTBRequest)
91+
if err != nil {
92+
return nil, []error{err}
93+
}
94+
95+
return []*adapters.RequestData{{
96+
Method: http.MethodPost,
97+
Body: reqJSON,
98+
Uri: url,
99+
Headers: *GetHeaders(openRTBRequest),
100+
}}, nil
101+
}
102+
103+
func (a *SmartyAdsAdapter) getImpressionExt(imp *openrtb.Imp) (*openrtb_ext.ExtSmartyAds, error) {
104+
var bidderExt adapters.ExtImpBidder
105+
if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil {
106+
return nil, &errortypes.BadInput{
107+
Message: "ext.bidder not provided",
108+
}
109+
}
110+
var smartyadsExt openrtb_ext.ExtSmartyAds
111+
if err := json.Unmarshal(bidderExt.Bidder, &smartyadsExt); err != nil {
112+
return nil, &errortypes.BadInput{
113+
Message: "ext.bidder not provided",
114+
}
115+
}
116+
return &smartyadsExt, nil
117+
}
118+
119+
func (a *SmartyAdsAdapter) buildEndpointURL(params *openrtb_ext.ExtSmartyAds) (string, error) {
120+
endpointParams := macros.EndpointTemplateParams{Host: params.Host, SourceId: params.SourceID, AccountID: params.AccountID}
121+
return macros.ResolveMacros(a.endpoint, endpointParams)
122+
}
123+
124+
func (a *SmartyAdsAdapter) CheckResponseStatusCodes(response *adapters.ResponseData) error {
125+
if response.StatusCode == http.StatusNoContent {
126+
return &errortypes.BadInput{Message: "No bid response"}
127+
}
128+
129+
if response.StatusCode == http.StatusBadRequest {
130+
return &errortypes.BadInput{
131+
Message: fmt.Sprintf("Unexpected status code: [ %d ]", response.StatusCode),
132+
}
133+
}
134+
135+
if response.StatusCode == http.StatusServiceUnavailable {
136+
return &errortypes.BadInput{
137+
Message: fmt.Sprintf("Something went wrong, please contact your Account Manager. Status Code: [ %d ] ", response.StatusCode),
138+
}
139+
}
140+
141+
if response.StatusCode < http.StatusOK || response.StatusCode >= http.StatusMultipleChoices {
142+
return &errortypes.BadInput{
143+
Message: fmt.Sprintf("Something went wrong, please contact your Account Manager. Status Code: [ %d ] ", response.StatusCode),
144+
}
145+
}
146+
147+
return nil
148+
}
149+
150+
func (a *SmartyAdsAdapter) MakeBids(
151+
openRTBRequest *openrtb.BidRequest,
152+
requestToBidder *adapters.RequestData,
153+
bidderRawResponse *adapters.ResponseData,
154+
) (
155+
bidderResponse *adapters.BidderResponse,
156+
errs []error,
157+
) {
158+
httpStatusError := a.CheckResponseStatusCodes(bidderRawResponse)
159+
if httpStatusError != nil {
160+
return nil, []error{httpStatusError}
161+
}
162+
163+
responseBody := bidderRawResponse.Body
164+
var bidResp openrtb.BidResponse
165+
if err := json.Unmarshal(responseBody, &bidResp); err != nil {
166+
return nil, []error{&errortypes.BadServerResponse{
167+
Message: "Bad Server Response",
168+
}}
169+
}
170+
171+
if len(bidResp.SeatBid) == 0 {
172+
return nil, []error{&errortypes.BadServerResponse{
173+
Message: "Empty SeatBid array",
174+
}}
175+
}
176+
177+
bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(bidResp.SeatBid[0].Bid))
178+
sb := bidResp.SeatBid[0]
179+
180+
for _, bid := range sb.Bid {
181+
bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
182+
Bid: &bid,
183+
BidType: getMediaTypeForImp(bid.ImpID, openRTBRequest.Imp),
184+
})
185+
}
186+
return bidResponse, nil
187+
}
188+
189+
func getMediaTypeForImp(impId string, imps []openrtb.Imp) openrtb_ext.BidType {
190+
mediaType := openrtb_ext.BidTypeBanner
191+
for _, imp := range imps {
192+
if imp.ID == impId {
193+
if imp.Video != nil {
194+
mediaType = openrtb_ext.BidTypeVideo
195+
} else if imp.Native != nil {
196+
mediaType = openrtb_ext.BidTypeNative
197+
}
198+
return mediaType
199+
}
200+
}
201+
return mediaType
202+
}

adapters/smartyads/smartyads_test.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package smartyads
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, "smartyadstest", NewSmartyAdsBidder("http://{{.Host}}.example.com/bid?rtb_seat_id={{.SourceId}}&secret_key={{.AccountID}}"))
11+
}

0 commit comments

Comments
 (0)