Skip to content

Commit

Permalink
Smarty ads adapter (prebid#1500)
Browse files Browse the repository at this point in the history
Co-authored-by: Kushneryk Pavlo <[email protected]>
Co-authored-by: user <[email protected]>
  • Loading branch information
3 people authored Oct 1, 2020
1 parent 2d03b85 commit 1e9ecd4
Show file tree
Hide file tree
Showing 29 changed files with 1,953 additions and 0 deletions.
52 changes: 52 additions & 0 deletions adapters/smartyads/params_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package smartyads

import (
"encoding/json"
"testing"

"github.com/prebid/prebid-server/openrtb_ext"
)

var validParams = []string{
`{ "host": "ep1", "sourceid": "partner", "accountid": "hash" }`,
}

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.BidderSmartyAds, json.RawMessage(validParam)); err != nil {
t.Errorf("Schema rejected SmartyAds params: %s", validParam)
}
}
}

var invalidParams = []string{
``,
`null`,
`true`,
`5`,
`4.2`,
`[]`,
`{}`,
`{"adCode": "string", "seatCode": 5, "originalPublisherid": "string"}`,
`{ "host": "ep1", "sourceid": "partner" }`,
`{ "host": "ep1, "accountid": "hash" }`,
`{ "sourceid": "partner", "sourceid": "partner" }`,
}

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.BidderSmartyAds, json.RawMessage(invalidParam)); err == nil {
t.Errorf("Schema allowed unexpected params: %s", invalidParam)
}
}
}
202 changes: 202 additions & 0 deletions adapters/smartyads/smartyads.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
package smartyads

import (
"encoding/json"
"fmt"
"net/http"
"strconv"
"text/template"

"github.com/mxmCherry/openrtb"
"github.com/prebid/prebid-server/adapters"
"github.com/prebid/prebid-server/errortypes"
"github.com/prebid/prebid-server/macros"
"github.com/prebid/prebid-server/openrtb_ext"
)

type SmartyAdsAdapter struct {
endpoint template.Template
}

func NewSmartyAdsBidder(endpointTemplate string) *SmartyAdsAdapter {
template, err := template.New("endpointTemplate").Parse(endpointTemplate)
if err != nil {
return nil
}
return &SmartyAdsAdapter{endpoint: *template}
}

func GetHeaders(request *openrtb.BidRequest) *http.Header {
headers := http.Header{}
headers.Add("Content-Type", "application/json;charset=utf-8")
headers.Add("Accept", "application/json")
headers.Add("X-Openrtb-Version", "2.5")

if request.Device != nil {
if len(request.Device.UA) > 0 {
headers.Add("User-Agent", request.Device.UA)
}

if len(request.Device.IPv6) > 0 {
headers.Add("X-Forwarded-For", request.Device.IPv6)
}

if len(request.Device.IP) > 0 {
headers.Add("X-Forwarded-For", request.Device.IP)
}

if len(request.Device.Language) > 0 {
headers.Add("Accept-Language", request.Device.Language)
}

if request.Device.DNT != nil {
headers.Add("Dnt", strconv.Itoa(int(*request.Device.DNT)))
}
}

return &headers
}

func (a *SmartyAdsAdapter) MakeRequests(
openRTBRequest *openrtb.BidRequest,
reqInfo *adapters.ExtraRequestInfo,
) (
requestsToBidder []*adapters.RequestData,
errs []error,
) {

var errors []error
var smartyadsExt *openrtb_ext.ExtSmartyAds
var err error

for i, imp := range openRTBRequest.Imp {
smartyadsExt, err = a.getImpressionExt(&imp)
if err != nil {
errors = append(errors, err)
break
}
openRTBRequest.Imp[i].Ext = nil
}

if len(errors) > 0 {
return nil, errors
}

url, err := a.buildEndpointURL(smartyadsExt)
if err != nil {
return nil, []error{err}
}

reqJSON, err := json.Marshal(openRTBRequest)
if err != nil {
return nil, []error{err}
}

return []*adapters.RequestData{{
Method: http.MethodPost,
Body: reqJSON,
Uri: url,
Headers: *GetHeaders(openRTBRequest),
}}, nil
}

func (a *SmartyAdsAdapter) getImpressionExt(imp *openrtb.Imp) (*openrtb_ext.ExtSmartyAds, error) {
var bidderExt adapters.ExtImpBidder
if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil {
return nil, &errortypes.BadInput{
Message: "ext.bidder not provided",
}
}
var smartyadsExt openrtb_ext.ExtSmartyAds
if err := json.Unmarshal(bidderExt.Bidder, &smartyadsExt); err != nil {
return nil, &errortypes.BadInput{
Message: "ext.bidder not provided",
}
}
return &smartyadsExt, nil
}

func (a *SmartyAdsAdapter) buildEndpointURL(params *openrtb_ext.ExtSmartyAds) (string, error) {
endpointParams := macros.EndpointTemplateParams{Host: params.Host, SourceId: params.SourceID, AccountID: params.AccountID}
return macros.ResolveMacros(a.endpoint, endpointParams)
}

func (a *SmartyAdsAdapter) CheckResponseStatusCodes(response *adapters.ResponseData) error {
if response.StatusCode == http.StatusNoContent {
return &errortypes.BadInput{Message: "No bid response"}
}

if response.StatusCode == http.StatusBadRequest {
return &errortypes.BadInput{
Message: fmt.Sprintf("Unexpected status code: [ %d ]", response.StatusCode),
}
}

if response.StatusCode == http.StatusServiceUnavailable {
return &errortypes.BadInput{
Message: fmt.Sprintf("Something went wrong, please contact your Account Manager. Status Code: [ %d ] ", response.StatusCode),
}
}

if response.StatusCode < http.StatusOK || response.StatusCode >= http.StatusMultipleChoices {
return &errortypes.BadInput{
Message: fmt.Sprintf("Something went wrong, please contact your Account Manager. Status Code: [ %d ] ", response.StatusCode),
}
}

return nil
}

func (a *SmartyAdsAdapter) MakeBids(
openRTBRequest *openrtb.BidRequest,
requestToBidder *adapters.RequestData,
bidderRawResponse *adapters.ResponseData,
) (
bidderResponse *adapters.BidderResponse,
errs []error,
) {
httpStatusError := a.CheckResponseStatusCodes(bidderRawResponse)
if httpStatusError != nil {
return nil, []error{httpStatusError}
}

responseBody := bidderRawResponse.Body
var bidResp openrtb.BidResponse
if err := json.Unmarshal(responseBody, &bidResp); err != nil {
return nil, []error{&errortypes.BadServerResponse{
Message: "Bad Server Response",
}}
}

if len(bidResp.SeatBid) == 0 {
return nil, []error{&errortypes.BadServerResponse{
Message: "Empty SeatBid array",
}}
}

bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(bidResp.SeatBid[0].Bid))
sb := bidResp.SeatBid[0]

for _, bid := range sb.Bid {
bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
Bid: &bid,
BidType: getMediaTypeForImp(bid.ImpID, openRTBRequest.Imp),
})
}
return bidResponse, nil
}

func getMediaTypeForImp(impId string, imps []openrtb.Imp) openrtb_ext.BidType {
mediaType := openrtb_ext.BidTypeBanner
for _, imp := range imps {
if imp.ID == impId {
if imp.Video != nil {
mediaType = openrtb_ext.BidTypeVideo
} else if imp.Native != nil {
mediaType = openrtb_ext.BidTypeNative
}
return mediaType
}
}
return mediaType
}
11 changes: 11 additions & 0 deletions adapters/smartyads/smartyads_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package smartyads

import (
"testing"

"github.com/prebid/prebid-server/adapters/adapterstest"
)

func TestJsonSamples(t *testing.T) {
adapterstest.RunJSONBidderTest(t, "smartyadstest", NewSmartyAdsBidder("http://{{.Host}}.example.com/bid?rtb_seat_id={{.SourceId}}&secret_key={{.AccountID}}"))
}
Loading

0 comments on commit 1e9ecd4

Please sign in to comment.