Skip to content

Commit f45db3d

Browse files
authored
New Adapter: Ogury (prebid#4082)
1 parent bc8e595 commit f45db3d

15 files changed

+936
-0
lines changed

adapters/ogury/ogury.go

+178
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
package ogury
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"net/http"
7+
"strings"
8+
9+
"github.com/prebid/openrtb/v20/openrtb2"
10+
11+
"github.com/prebid/prebid-server/v3/adapters"
12+
"github.com/prebid/prebid-server/v3/config"
13+
"github.com/prebid/prebid-server/v3/errortypes"
14+
"github.com/prebid/prebid-server/v3/openrtb_ext"
15+
"github.com/prebid/prebid-server/v3/util/jsonutil"
16+
)
17+
18+
type adapter struct {
19+
endpoint string
20+
}
21+
22+
func Builder(_ openrtb_ext.BidderName, config config.Adapter, _ config.Server) (adapters.Bidder, error) {
23+
return &adapter{endpoint: config.Endpoint}, nil
24+
}
25+
26+
func (a adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
27+
headers := buildHeaders(request)
28+
29+
var errors []error
30+
var impsWithOguryParams []openrtb2.Imp
31+
for i, imp := range request.Imp {
32+
var impExt, impExtBidderHoist map[string]json.RawMessage
33+
// extract ext
34+
if err := jsonutil.Unmarshal(imp.Ext, &impExt); err != nil {
35+
return nil, append(errors, &errortypes.BadInput{
36+
Message: "Bidder extension not provided or can't be unmarshalled",
37+
})
38+
}
39+
// find Ogury bidder params
40+
if bidder, ok := impExt[openrtb_ext.PrebidExtBidderKey]; ok {
41+
if err := jsonutil.Unmarshal(bidder, &impExtBidderHoist); err != nil {
42+
return nil, append(errors, &errortypes.BadInput{
43+
Message: "Ogury bidder extension not provided or can't be unmarshalled",
44+
})
45+
}
46+
}
47+
48+
// extract every value from imp[].ext.bidder to imp[].ext
49+
for key, value := range impExtBidderHoist {
50+
impExt[key] = value
51+
}
52+
delete(impExt, openrtb_ext.PrebidExtBidderKey)
53+
54+
ext, err := jsonutil.Marshal(impExt)
55+
if err != nil {
56+
return nil, append(errors, &errortypes.BadInput{
57+
Message: "Error while marshaling Imp.Ext bidder extension",
58+
})
59+
}
60+
request.Imp[i].Ext = ext
61+
62+
// save adUnitCode
63+
request.Imp[i].TagID = imp.ID
64+
65+
// currency conversion
66+
// Check if imp comes with bid floor amount defined in a foreign currency
67+
if imp.BidFloor > 0 && imp.BidFloorCur != "" && strings.ToUpper(imp.BidFloorCur) != "USD" {
68+
69+
// Convert to US dollars
70+
convertedValue, err := requestInfo.ConvertCurrency(imp.BidFloor, imp.BidFloorCur, "USD")
71+
if err != nil {
72+
return nil, []error{err}
73+
}
74+
75+
// Update after conversion. All imp elements inside request.Imp are shallow copies
76+
// therefore, their non-pointer values are not shared memory and are safe to modify.
77+
request.Imp[i].BidFloorCur = "USD"
78+
request.Imp[i].BidFloor = convertedValue
79+
}
80+
81+
// check if imp has ogury params and filter it
82+
_, hasAssetKey := impExtBidderHoist["assetKey"]
83+
_, hasAdUnitId := impExtBidderHoist["adUnitId"]
84+
if hasAssetKey && hasAdUnitId {
85+
impsWithOguryParams = append(impsWithOguryParams, request.Imp[i])
86+
}
87+
}
88+
89+
if len(impsWithOguryParams) == 0 && (request.Site == nil || request.Site.Publisher.ID == "") {
90+
return nil, []error{&errortypes.BadInput{
91+
Message: "Invalid request. assetKey/adUnitId or request.site.publisher.id required",
92+
}}
93+
} else if len(impsWithOguryParams) > 0 {
94+
request.Imp = impsWithOguryParams
95+
}
96+
97+
requestJSON, err := jsonutil.Marshal(request)
98+
if err != nil {
99+
return nil, []error{err}
100+
}
101+
102+
requestData := &adapters.RequestData{
103+
Method: "POST",
104+
Uri: a.endpoint,
105+
Body: requestJSON,
106+
Headers: headers,
107+
ImpIDs: openrtb_ext.GetImpIDs(request.Imp),
108+
}
109+
110+
return []*adapters.RequestData{requestData}, nil
111+
112+
}
113+
114+
func buildHeaders(request *openrtb2.BidRequest) http.Header {
115+
headers := http.Header{}
116+
headers.Add("Content-Type", "application/json;charset=utf-8")
117+
if request.Device != nil {
118+
headers.Add("X-Forwarded-For", request.Device.IP)
119+
headers.Add("X-Forwarded-For", request.Device.IPv6)
120+
headers.Add("User-Agent", request.Device.UA)
121+
headers.Add("Accept-Language", request.Device.Language)
122+
}
123+
return headers
124+
125+
}
126+
127+
func getMediaTypeForBid(bid openrtb2.Bid) (openrtb_ext.BidType, error) {
128+
switch bid.MType {
129+
case openrtb2.MarkupBanner:
130+
return openrtb_ext.BidTypeBanner, nil
131+
case openrtb2.MarkupAudio:
132+
return openrtb_ext.BidTypeAudio, nil
133+
case openrtb2.MarkupNative:
134+
return openrtb_ext.BidTypeNative, nil
135+
case openrtb2.MarkupVideo:
136+
return openrtb_ext.BidTypeVideo, nil
137+
default:
138+
return "", &errortypes.BadServerResponse{
139+
Message: fmt.Sprintf("Unsupported MType \"%d\", for impression \"%s\"", bid.MType, bid.ImpID),
140+
}
141+
}
142+
}
143+
144+
func (a adapter) MakeBids(request *openrtb2.BidRequest, _ *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) {
145+
if adapters.IsResponseStatusCodeNoContent(responseData) {
146+
return nil, nil
147+
}
148+
if err := adapters.CheckResponseStatusCodeForErrors(responseData); err != nil {
149+
return nil, []error{err}
150+
}
151+
152+
var response openrtb2.BidResponse
153+
if err := jsonutil.Unmarshal(responseData.Body, &response); err != nil {
154+
return nil, []error{err}
155+
}
156+
157+
bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(request.Imp))
158+
bidResponse.Currency = response.Cur
159+
var errors []error
160+
for _, seatBid := range response.SeatBid {
161+
for i, bid := range seatBid.Bid {
162+
bidType, err := getMediaTypeForBid(bid)
163+
if err != nil {
164+
errors = append(errors, err)
165+
continue
166+
}
167+
bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
168+
Bid: &seatBid.Bid[i],
169+
BidType: bidType,
170+
})
171+
}
172+
}
173+
if errors != nil {
174+
return nil, errors
175+
}
176+
177+
return bidResponse, nil
178+
}

adapters/ogury/ogury_test.go

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package ogury
2+
3+
import (
4+
"testing"
5+
6+
"github.com/prebid/prebid-server/v3/adapters/adapterstest"
7+
"github.com/prebid/prebid-server/v3/config"
8+
"github.com/prebid/prebid-server/v3/openrtb_ext"
9+
)
10+
11+
func TestJsonSamples(t *testing.T) {
12+
bidder, buildErr := Builder(openrtb_ext.BidderOgury, config.Adapter{
13+
Endpoint: "http://ogury.example.com"},
14+
config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"})
15+
16+
if buildErr != nil {
17+
t.Fatalf("Builder returned unexpected error %v", buildErr)
18+
}
19+
20+
adapterstest.RunJSONBidderTest(t, "ogurytest", bidder)
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
{
2+
"mockBidRequest": {
3+
"id": "test-request-id",
4+
"imp": [
5+
{
6+
"id": "ad-unit-code-as-imp-id",
7+
"banner": {
8+
"format": [{"w": 128, "h": 100}]
9+
},
10+
"ext": {
11+
"gpid": "global position id",
12+
"bidder": {
13+
"assetKey": "OGY",
14+
"adUnitId": "123"
15+
}
16+
}
17+
}
18+
]
19+
},
20+
21+
"httpCalls": [
22+
{
23+
"expectedRequest": {
24+
"uri": "http://ogury.example.com",
25+
"body": {
26+
"id": "test-request-id",
27+
"imp": [
28+
{
29+
"id":"ad-unit-code-as-imp-id",
30+
"tagid": "ad-unit-code-as-imp-id",
31+
"banner": {
32+
"format": [{"w": 128, "h": 100}]
33+
},
34+
"ext": {
35+
"gpid": "global position id",
36+
"assetKey": "OGY",
37+
"adUnitId": "123"
38+
}
39+
}
40+
]
41+
},
42+
"impIDs":["ad-unit-code-as-imp-id"]
43+
},
44+
"mockResponse": {
45+
"status": 200,
46+
"body": {
47+
"id": "test-request-id",
48+
"cur": "USD",
49+
"seatbid": [
50+
{
51+
"seat": "seat",
52+
"bid": [{
53+
"id": "some-UUID",
54+
"impid": "ad-unit-code-as-imp-id",
55+
"price": 0.500000,
56+
"adm": "adm string",
57+
"crid": "crid_10",
58+
"h": 100,
59+
"w": 128,
60+
"mtype": 1
61+
}]
62+
}
63+
]
64+
}
65+
}
66+
}
67+
],
68+
69+
"expectedBidResponses": [
70+
{
71+
"currency": "USD",
72+
"bids": [
73+
{
74+
"bid": {
75+
"id": "some-UUID",
76+
"impid": "ad-unit-code-as-imp-id",
77+
"price": 0.5,
78+
"adm": "adm string",
79+
"crid": "crid_10",
80+
"h": 100,
81+
"w": 128,
82+
"mtype": 1
83+
},
84+
"type": "banner"
85+
}
86+
]
87+
}
88+
]
89+
}

0 commit comments

Comments
 (0)