From 13c7cb0e95d68e6203e1c15938b3884acd3c52b4 Mon Sep 17 00:00:00 2001 From: Natalia Castiglioni Date: Tue, 24 Oct 2023 10:48:32 -0300 Subject: [PATCH] Add product support for gg --- adapters/gumgum/gumgum.go | 400 ++++++++++++++++--------------- adapters/gumgum/params_test.go | 96 ++++---- openrtb_ext/imp_gumgum.go | 19 +- static/bidder-params/gumgum.json | 6 +- 4 files changed, 265 insertions(+), 256 deletions(-) diff --git a/adapters/gumgum/gumgum.go b/adapters/gumgum/gumgum.go index 3b954bf5837..aeca5b32b16 100644 --- a/adapters/gumgum/gumgum.go +++ b/adapters/gumgum/gumgum.go @@ -1,230 +1,234 @@ package gumgum import ( - "encoding/json" - "fmt" - "net/http" - "strconv" - "strings" - - "github.com/prebid/openrtb/v19/openrtb2" - "github.com/prebid/prebid-server/v2/adapters" - "github.com/prebid/prebid-server/v2/config" - "github.com/prebid/prebid-server/v2/errortypes" - "github.com/prebid/prebid-server/v2/openrtb_ext" + "encoding/json" + "fmt" + "net/http" + "strconv" + "strings" + + "github.com/prebid/openrtb/v19/openrtb2" + "github.com/prebid/prebid-server/adapters" + "github.com/prebid/prebid-server/config" + "github.com/prebid/prebid-server/errortypes" + "github.com/prebid/prebid-server/openrtb_ext" ) // GumGumAdapter implements Bidder interface. type GumGumAdapter struct { - URI string + URI string } // MakeRequests makes the HTTP requests which should be made to fetch bids. func (g *GumGumAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { - var validImps []openrtb2.Imp - var siteCopy openrtb2.Site - if request.Site != nil { - siteCopy = *request.Site - } - - numRequests := len(request.Imp) - errs := make([]error, 0, numRequests) - - for i := 0; i < numRequests; i++ { - imp := request.Imp[i] - gumgumExt, err := preprocess(&imp) - if err != nil { - errs = append(errs, err) - } else { - if gumgumExt.Zone != "" { - siteCopy.ID = gumgumExt.Zone - } - - if gumgumExt.PubID != 0 { - if siteCopy.Publisher != nil { - siteCopy.Publisher.ID = strconv.FormatFloat(gumgumExt.PubID, 'f', -1, 64) - } else { - siteCopy.Publisher = &openrtb2.Publisher{ID: strconv.FormatFloat(gumgumExt.PubID, 'f', -1, 64)} - } - } - - validImps = append(validImps, imp) - } - } - - if len(validImps) == 0 { - return nil, errs - } - - request.Imp = validImps - - if request.Site != nil { - request.Site = &siteCopy - } - - 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: g.URI, - Body: reqJSON, - Headers: headers, - }}, errs + var validImps []openrtb2.Imp + var siteCopy openrtb2.Site + if request.Site != nil { + siteCopy = *request.Site + } + + numRequests := len(request.Imp) + errs := make([]error, 0, numRequests) + + for i := 0; i < numRequests; i++ { + imp := request.Imp[i] + gumgumExt, err := preprocess(&imp) + if err != nil { + errs = append(errs, err) + } else { + if gumgumExt.Zone != "" { + siteCopy.ID = gumgumExt.Zone + } + + if gumgumExt.PubID != 0 { + if siteCopy.Publisher != nil { + siteCopy.Publisher.ID = strconv.FormatFloat(gumgumExt.PubID, 'f', -1, 64) + } else { + siteCopy.Publisher = &openrtb2.Publisher{ID: strconv.FormatFloat(gumgumExt.PubID, 'f', -1, 64)} + } + } + + validImps = append(validImps, imp) + } + } + + if len(validImps) == 0 { + return nil, errs + } + + request.Imp = validImps + + if request.Site != nil { + request.Site = &siteCopy + } + + 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: g.URI, + Body: reqJSON, + Headers: headers, + }}, errs } // MakeBids unpacks the server's response into Bids. func (g *GumGumAdapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) { - if response.StatusCode == http.StatusNoContent { - return nil, nil - } - - if response.StatusCode == http.StatusBadRequest { - return nil, []error{&errortypes.BadInput{ - Message: fmt.Sprintf("Bad user input: HTTP status %d", response.StatusCode), - }} - } - - if response.StatusCode != http.StatusOK { - return nil, []error{&errortypes.BadServerResponse{ - Message: fmt.Sprintf("Bad server response: HTTP status %d", response.StatusCode), - }} - } - var bidResp openrtb2.BidResponse - if err := json.Unmarshal(response.Body, &bidResp); err != nil { - return nil, []error{&errortypes.BadServerResponse{ - Message: fmt.Sprintf("Bad server response: %d. ", err), - }} - } - - var errs []error - bidResponse := adapters.NewBidderResponseWithBidsCapacity(5) - - for _, sb := range bidResp.SeatBid { - for i := range sb.Bid { - mediaType := getMediaTypeForImpID(sb.Bid[i].ImpID, internalRequest.Imp) - if mediaType == openrtb_ext.BidTypeVideo { - price := strconv.FormatFloat(sb.Bid[i].Price, 'f', -1, 64) - sb.Bid[i].AdM = strings.Replace(sb.Bid[i].AdM, "${AUCTION_PRICE}", price, -1) - } - - bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ - Bid: &sb.Bid[i], - BidType: mediaType, - }) - } - } - - return bidResponse, errs + if response.StatusCode == http.StatusNoContent { + return nil, nil + } + + if response.StatusCode == http.StatusBadRequest { + return nil, []error{&errortypes.BadInput{ + Message: fmt.Sprintf("Bad user input: HTTP status %d", response.StatusCode), + }} + } + + if response.StatusCode != http.StatusOK { + return nil, []error{&errortypes.BadServerResponse{ + Message: fmt.Sprintf("Bad server response: HTTP status %d", response.StatusCode), + }} + } + var bidResp openrtb2.BidResponse + if err := json.Unmarshal(response.Body, &bidResp); err != nil { + return nil, []error{&errortypes.BadServerResponse{ + Message: fmt.Sprintf("Bad server response: %d. ", err), + }} + } + + var errs []error + bidResponse := adapters.NewBidderResponseWithBidsCapacity(5) + + for _, sb := range bidResp.SeatBid { + for i := range sb.Bid { + mediaType := getMediaTypeForImpID(sb.Bid[i].ImpID, internalRequest.Imp) + if mediaType == openrtb_ext.BidTypeVideo { + price := strconv.FormatFloat(sb.Bid[i].Price, 'f', -1, 64) + sb.Bid[i].AdM = strings.Replace(sb.Bid[i].AdM, "${AUCTION_PRICE}", price, -1) + } + + bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ + Bid: &sb.Bid[i], + BidType: mediaType, + }) + } + } + + return bidResponse, errs } func preprocess(imp *openrtb2.Imp) (*openrtb_ext.ExtImpGumGum, error) { - var bidderExt adapters.ExtImpBidder - if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil { - err = &errortypes.BadInput{ - Message: err.Error(), - } - return nil, err - } - - var gumgumExt openrtb_ext.ExtImpGumGum - if err := json.Unmarshal(bidderExt.Bidder, &gumgumExt); err != nil { - err = &errortypes.BadInput{ - Message: err.Error(), - } - return nil, err - } - - if imp.Banner != nil && imp.Banner.W == nil && imp.Banner.H == nil && len(imp.Banner.Format) > 0 { - bannerCopy := *imp.Banner - format := bannerCopy.Format[0] - bannerCopy.W = &(format.W) - bannerCopy.H = &(format.H) - - if gumgumExt.Slot != 0 { - var err error - bannerExt := getBiggerFormat(bannerCopy.Format, gumgumExt.Slot) - bannerCopy.Ext, err = json.Marshal(&bannerExt) - if err != nil { - return nil, err - } - } - - imp.Banner = &bannerCopy - } - - if imp.Video != nil { - err := validateVideoParams(imp.Video) - if err != nil { - return nil, err - } - - if gumgumExt.IrisID != "" { - videoCopy := *imp.Video - videoExt := openrtb_ext.ExtImpGumGumVideo{IrisID: gumgumExt.IrisID} - videoCopy.Ext, err = json.Marshal(&videoExt) - if err != nil { - return nil, err - } - imp.Video = &videoCopy - } - } - - return &gumgumExt, nil + var bidderExt adapters.ExtImpBidder + if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil { + err = &errortypes.BadInput{ + Message: err.Error(), + } + return nil, err + } + + var gumgumExt openrtb_ext.ExtImpGumGum + if err := json.Unmarshal(bidderExt.Bidder, &gumgumExt); err != nil { + err = &errortypes.BadInput{ + Message: err.Error(), + } + return nil, err + } + + if imp.Banner != nil && imp.Banner.W == nil && imp.Banner.H == nil && len(imp.Banner.Format) > 0 { + bannerCopy := *imp.Banner + format := bannerCopy.Format[0] + bannerCopy.W = &(format.W) + bannerCopy.H = &(format.H) + + if gumgumExt.Slot != 0 { + var err error + bannerExt := getBiggerFormat(bannerCopy.Format, gumgumExt.Slot) + bannerCopy.Ext, err = json.Marshal(&bannerExt) + if err != nil { + return nil, err + } + } + + imp.Banner = &bannerCopy + } + + if imp.Video != nil { + err := validateVideoParams(imp.Video) + if err != nil { + return nil, err + } + + if gumgumExt.IrisID != "" { + videoCopy := *imp.Video + videoExt := openrtb_ext.ExtImpGumGumVideo{IrisID: gumgumExt.IrisID} + videoCopy.Ext, err = json.Marshal(&videoExt) + if err != nil { + return nil, err + } + imp.Video = &videoCopy + } + } + + if gumgumExt.Product != "" { + imp.Ext = json.RawMessage(fmt.Sprintf(`{ "product": "%s" }`, gumgumExt.Product)) + } + + return &gumgumExt, nil } func getBiggerFormat(formatList []openrtb2.Format, slot float64) openrtb_ext.ExtImpGumGumBanner { - maxw := int64(0) - maxh := int64(0) - greatestVal := int64(0) - for _, size := range formatList { - var biggerSide int64 - if size.W > size.H { - biggerSide = size.W - } else { - biggerSide = size.H - } - - if biggerSide > greatestVal || (biggerSide == greatestVal && size.W >= maxw && size.H >= maxh) { - greatestVal = biggerSide - maxh = size.H - maxw = size.W - } - } - - bannerExt := openrtb_ext.ExtImpGumGumBanner{Si: slot, MaxW: float64(maxw), MaxH: float64(maxh)} - - return bannerExt + maxw := int64(0) + maxh := int64(0) + greatestVal := int64(0) + for _, size := range formatList { + var biggerSide int64 + if size.W > size.H { + biggerSide = size.W + } else { + biggerSide = size.H + } + + if biggerSide > greatestVal || (biggerSide == greatestVal && size.W >= maxw && size.H >= maxh) { + greatestVal = biggerSide + maxh = size.H + maxw = size.W + } + } + + bannerExt := openrtb_ext.ExtImpGumGumBanner{Si: slot, MaxW: float64(maxw), MaxH: float64(maxh)} + + return bannerExt } func getMediaTypeForImpID(impID string, imps []openrtb2.Imp) openrtb_ext.BidType { - for _, imp := range imps { - if imp.ID == impID && imp.Banner != nil { - return openrtb_ext.BidTypeBanner - } - } - return openrtb_ext.BidTypeVideo + for _, imp := range imps { + if imp.ID == impID && imp.Banner != nil { + return openrtb_ext.BidTypeBanner + } + } + return openrtb_ext.BidTypeVideo } func validateVideoParams(video *openrtb2.Video) (err error) { - if video.W == 0 || video.H == 0 || video.MinDuration == 0 || video.MaxDuration == 0 || video.Placement == 0 || video.Linearity == 0 { - return &errortypes.BadInput{ - Message: "Invalid or missing video field(s)", - } - } - return nil + if video.W == 0 || video.H == 0 || video.MinDuration == 0 || video.MaxDuration == 0 || video.Placement == 0 || video.Linearity == 0 { + return &errortypes.BadInput{ + Message: "Invalid or missing video field(s)", + } + } + return nil } // Builder builds a new instance of the GumGum adapter for the given bidder with the given config. func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { - bidder := &GumGumAdapter{ - URI: config.Endpoint, - } - return bidder, nil + bidder := &GumGumAdapter{ + URI: config.Endpoint, + } + return bidder, nil } diff --git a/adapters/gumgum/params_test.go b/adapters/gumgum/params_test.go index afee017be03..c5848194c5b 100644 --- a/adapters/gumgum/params_test.go +++ b/adapters/gumgum/params_test.go @@ -1,65 +1,65 @@ package gumgum import ( - "encoding/json" - "testing" - - "github.com/prebid/prebid-server/v2/openrtb_ext" + "encoding/json" + "github.com/prebid/prebid-server/openrtb_ext" + "testing" ) 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) - } + 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.BidderGumGum, json.RawMessage(validParam)); err != nil { - t.Errorf("Schema rejected gumgum params: %s", validParam) - } - } + for _, validParam := range validParams { + if err := validator.Validate(openrtb_ext.BidderGumGum, json.RawMessage(validParam)); err != nil { + t.Errorf("Schema rejected gumgum params: %s", validParam) + } + } } 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) - } + 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.BidderGumGum, json.RawMessage(invalidParam)); err == nil { - t.Errorf("Schema allowed unexpected params: %s", invalidParam) - } - } + for _, invalidParam := range invalidParams { + if err := validator.Validate(openrtb_ext.BidderGumGum, json.RawMessage(invalidParam)); err == nil { + t.Errorf("Schema allowed unexpected params: %s", invalidParam) + } + } } var validParams = []string{ - `{"zone":"dc9d6be1"}`, - `{"pubId":12345678}`, - `{"zone":"dc9d6be1", "pubId":12345678}`, - `{"zone":"dc9d6be1", "slot":1234567}`, - `{"pubId":12345678, "slot":1234567}`, - `{"pubId":12345678, "irisid": "iris_6f9285823a48bne5"}`, - `{"zone":"dc9d6be1", "irisid": "iris_6f9285823a48bne5"}`, - `{"zone":"dc9d6be1", "pubId":12345678, "irisid": "iris_6f9285823a48bne5"}`, + `{"zone":"dc9d6be1"}`, + `{"pubId":12345678}`, + `{"zone":"dc9d6be1", "pubId":12345678}`, + `{"zone":"dc9d6be1", "slot":1234567}`, + `{"pubId":12345678, "slot":1234567}`, + `{"pubId":12345678, "irisid": "iris_6f9285823a48bne5"}`, + `{"zone":"dc9d6be1", "irisid": "iris_6f9285823a48bne5"}`, + `{"zone":"dc9d6be1", "pubId":12345678, "irisid": "iris_6f9285823a48bne5"}`, + `{"zone":"dc9d6be1", "pubId":12345678, "irisid": "iris_6f9285823a48bne5", "product": "skins"}`, } var invalidParams = []string{ - `null`, - `nil`, - ``, - `{}`, - `[]`, - `true`, - `2`, - `{"zone":12345678}`, - `{"zone":""}`, - `{"placementId": 1}`, - `{"zone": true}`, - `{"placementId": 1, "zone":"1234567"}`, - `{"pubId":"123456"}`, - `{"slot":123456}`, - `{"zone":"1234567", "irisid": ""}`, - `{"zone":"1234567", "irisid": 1234}`, - `{"irisid": "iris_6f9285823a48bne5"}`, -} + `null`, + `nil`, + ``, + `{}`, + `[]`, + `true`, + `2`, + `{"zone":12345678}`, + `{"zone":""}`, + `{"placementId": 1}`, + `{"zone": true}`, + `{"placementId": 1, "zone":"1234567"}`, + `{"pubId":"123456"}`, + `{"slot":123456}`, + `{"zone":"1234567", "irisid": ""}`, + `{"zone":"1234567", "irisid": 1234}`, + `{"irisid": "iris_6f9285823a48bne5"}`, +} \ No newline at end of file diff --git a/openrtb_ext/imp_gumgum.go b/openrtb_ext/imp_gumgum.go index 96a1308d663..4916f26395c 100644 --- a/openrtb_ext/imp_gumgum.go +++ b/openrtb_ext/imp_gumgum.go @@ -3,20 +3,21 @@ package openrtb_ext // ExtImpGumGum defines the contract for bidrequest.imp[i].ext.prebid.bidder.gumgum // Either Zone or PubId must be present, others are optional parameters type ExtImpGumGum struct { - Zone string `json:"zone,omitempty"` - PubID float64 `json:"pubId,omitempty"` - IrisID string `json:"irisid,omitempty"` - Slot float64 `json:"slot,omitempty"` + Zone string `json:"zone,omitempty"` + PubID float64 `json:"pubId,omitempty"` + IrisID string `json:"irisid,omitempty"` + Slot float64 `json:"slot,omitempty"` + Product string `json:"product,omitempty"` } // ExtImpGumGumVideo defines the contract for bidresponse.seatbid.bid[i].ext.prebid.bidder.gumgum.video type ExtImpGumGumVideo struct { - IrisID string `json:"irisid,omitempty"` + IrisID string `json:"irisid,omitempty"` } // ExtImpGumGumBanner defines the contract for bidresponse.seatbid.bid[i].ext.prebid.bidder.gumgum.banner type ExtImpGumGumBanner struct { - Si float64 `json:"si,omitempty"` - MaxW float64 `json:"maxw,omitempty"` - MaxH float64 `json:"maxh,omitempty"` -} + Si float64 `json:"si,omitempty"` + MaxW float64 `json:"maxw,omitempty"` + MaxH float64 `json:"maxh,omitempty"` +} \ No newline at end of file diff --git a/static/bidder-params/gumgum.json b/static/bidder-params/gumgum.json index 95f05e7d517..c9972713f87 100644 --- a/static/bidder-params/gumgum.json +++ b/static/bidder-params/gumgum.json @@ -20,6 +20,10 @@ "slot": { "type": "integer", "description": "A slot id used to identify a slot placement mapped to a GumGum zone or publisher" + }, + "product": { + "type": "string", + "description": "Product param that allow support for Desktop Skins - display and video" } }, "anyOf": [ @@ -34,4 +38,4 @@ ] } ] -} +} \ No newline at end of file