Skip to content

Commit

Permalink
New Adapter: Ogury (#4082)
Browse files Browse the repository at this point in the history
  • Loading branch information
krdzo authored Jan 24, 2025
1 parent bc8e595 commit f45db3d
Show file tree
Hide file tree
Showing 15 changed files with 936 additions and 0 deletions.
178 changes: 178 additions & 0 deletions adapters/ogury/ogury.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
package ogury

import (
"encoding/json"
"fmt"
"net/http"
"strings"

"github.com/prebid/openrtb/v20/openrtb2"

"github.com/prebid/prebid-server/v3/adapters"
"github.com/prebid/prebid-server/v3/config"
"github.com/prebid/prebid-server/v3/errortypes"
"github.com/prebid/prebid-server/v3/openrtb_ext"
"github.com/prebid/prebid-server/v3/util/jsonutil"
)

type adapter struct {
endpoint string
}

func Builder(_ openrtb_ext.BidderName, config config.Adapter, _ config.Server) (adapters.Bidder, error) {
return &adapter{endpoint: config.Endpoint}, nil
}

func (a adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
headers := buildHeaders(request)

var errors []error
var impsWithOguryParams []openrtb2.Imp
for i, imp := range request.Imp {
var impExt, impExtBidderHoist map[string]json.RawMessage
// extract ext
if err := jsonutil.Unmarshal(imp.Ext, &impExt); err != nil {
return nil, append(errors, &errortypes.BadInput{
Message: "Bidder extension not provided or can't be unmarshalled",
})
}
// find Ogury bidder params
if bidder, ok := impExt[openrtb_ext.PrebidExtBidderKey]; ok {
if err := jsonutil.Unmarshal(bidder, &impExtBidderHoist); err != nil {
return nil, append(errors, &errortypes.BadInput{
Message: "Ogury bidder extension not provided or can't be unmarshalled",
})
}
}

// extract every value from imp[].ext.bidder to imp[].ext
for key, value := range impExtBidderHoist {
impExt[key] = value
}
delete(impExt, openrtb_ext.PrebidExtBidderKey)

ext, err := jsonutil.Marshal(impExt)
if err != nil {
return nil, append(errors, &errortypes.BadInput{
Message: "Error while marshaling Imp.Ext bidder extension",
})
}
request.Imp[i].Ext = ext

// save adUnitCode
request.Imp[i].TagID = imp.ID

// currency conversion
// Check if imp comes with bid floor amount defined in a foreign currency
if imp.BidFloor > 0 && imp.BidFloorCur != "" && strings.ToUpper(imp.BidFloorCur) != "USD" {

// Convert to US dollars
convertedValue, err := requestInfo.ConvertCurrency(imp.BidFloor, imp.BidFloorCur, "USD")
if err != nil {
return nil, []error{err}
}

// Update after conversion. All imp elements inside request.Imp are shallow copies
// therefore, their non-pointer values are not shared memory and are safe to modify.
request.Imp[i].BidFloorCur = "USD"
request.Imp[i].BidFloor = convertedValue
}

// check if imp has ogury params and filter it
_, hasAssetKey := impExtBidderHoist["assetKey"]
_, hasAdUnitId := impExtBidderHoist["adUnitId"]
if hasAssetKey && hasAdUnitId {
impsWithOguryParams = append(impsWithOguryParams, request.Imp[i])
}
}

if len(impsWithOguryParams) == 0 && (request.Site == nil || request.Site.Publisher.ID == "") {
return nil, []error{&errortypes.BadInput{
Message: "Invalid request. assetKey/adUnitId or request.site.publisher.id required",
}}
} else if len(impsWithOguryParams) > 0 {
request.Imp = impsWithOguryParams
}

requestJSON, err := jsonutil.Marshal(request)
if err != nil {
return nil, []error{err}
}

requestData := &adapters.RequestData{
Method: "POST",
Uri: a.endpoint,
Body: requestJSON,
Headers: headers,
ImpIDs: openrtb_ext.GetImpIDs(request.Imp),
}

return []*adapters.RequestData{requestData}, nil

}

func buildHeaders(request *openrtb2.BidRequest) http.Header {
headers := http.Header{}
headers.Add("Content-Type", "application/json;charset=utf-8")
if request.Device != nil {
headers.Add("X-Forwarded-For", request.Device.IP)
headers.Add("X-Forwarded-For", request.Device.IPv6)
headers.Add("User-Agent", request.Device.UA)
headers.Add("Accept-Language", request.Device.Language)
}
return headers

}

func getMediaTypeForBid(bid openrtb2.Bid) (openrtb_ext.BidType, error) {
switch bid.MType {
case openrtb2.MarkupBanner:
return openrtb_ext.BidTypeBanner, nil
case openrtb2.MarkupAudio:
return openrtb_ext.BidTypeAudio, nil
case openrtb2.MarkupNative:
return openrtb_ext.BidTypeNative, nil
case openrtb2.MarkupVideo:
return openrtb_ext.BidTypeVideo, nil
default:
return "", &errortypes.BadServerResponse{
Message: fmt.Sprintf("Unsupported MType \"%d\", for impression \"%s\"", bid.MType, bid.ImpID),
}
}
}

func (a adapter) MakeBids(request *openrtb2.BidRequest, _ *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) {
if adapters.IsResponseStatusCodeNoContent(responseData) {
return nil, nil
}
if err := adapters.CheckResponseStatusCodeForErrors(responseData); err != nil {
return nil, []error{err}
}

var response openrtb2.BidResponse
if err := jsonutil.Unmarshal(responseData.Body, &response); err != nil {
return nil, []error{err}
}

bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(request.Imp))
bidResponse.Currency = response.Cur
var errors []error
for _, seatBid := range response.SeatBid {
for i, bid := range seatBid.Bid {
bidType, err := getMediaTypeForBid(bid)
if err != nil {
errors = append(errors, err)
continue
}
bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
Bid: &seatBid.Bid[i],
BidType: bidType,
})
}
}
if errors != nil {
return nil, errors
}

return bidResponse, nil
}
21 changes: 21 additions & 0 deletions adapters/ogury/ogury_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package ogury

import (
"testing"

"github.com/prebid/prebid-server/v3/adapters/adapterstest"
"github.com/prebid/prebid-server/v3/config"
"github.com/prebid/prebid-server/v3/openrtb_ext"
)

func TestJsonSamples(t *testing.T) {
bidder, buildErr := Builder(openrtb_ext.BidderOgury, config.Adapter{
Endpoint: "http://ogury.example.com"},
config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"})

if buildErr != nil {
t.Fatalf("Builder returned unexpected error %v", buildErr)
}

adapterstest.RunJSONBidderTest(t, "ogurytest", bidder)
}
89 changes: 89 additions & 0 deletions adapters/ogury/ogurytest/exemplary/banner_asset_ad_unit.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
{
"mockBidRequest": {
"id": "test-request-id",
"imp": [
{
"id": "ad-unit-code-as-imp-id",
"banner": {
"format": [{"w": 128, "h": 100}]
},
"ext": {
"gpid": "global position id",
"bidder": {
"assetKey": "OGY",
"adUnitId": "123"
}
}
}
]
},

"httpCalls": [
{
"expectedRequest": {
"uri": "http://ogury.example.com",
"body": {
"id": "test-request-id",
"imp": [
{
"id":"ad-unit-code-as-imp-id",
"tagid": "ad-unit-code-as-imp-id",
"banner": {
"format": [{"w": 128, "h": 100}]
},
"ext": {
"gpid": "global position id",
"assetKey": "OGY",
"adUnitId": "123"
}
}
]
},
"impIDs":["ad-unit-code-as-imp-id"]
},
"mockResponse": {
"status": 200,
"body": {
"id": "test-request-id",
"cur": "USD",
"seatbid": [
{
"seat": "seat",
"bid": [{
"id": "some-UUID",
"impid": "ad-unit-code-as-imp-id",
"price": 0.500000,
"adm": "adm string",
"crid": "crid_10",
"h": 100,
"w": 128,
"mtype": 1
}]
}
]
}
}
}
],

"expectedBidResponses": [
{
"currency": "USD",
"bids": [
{
"bid": {
"id": "some-UUID",
"impid": "ad-unit-code-as-imp-id",
"price": 0.5,
"adm": "adm string",
"crid": "crid_10",
"h": 100,
"w": 128,
"mtype": 1
},
"type": "banner"
}
]
}
]
}
Loading

0 comments on commit f45db3d

Please sign in to comment.