-
Notifications
You must be signed in to change notification settings - Fork 753
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
New Adapter: MeloZen #3784
New Adapter: MeloZen #3784
Changes from 6 commits
3bd35a8
d2cddf8
ef24067
1f345e9
e4fa1f8
aaf0f8f
6838e9e
29cb5f7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,185 @@ | ||
package melozen | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"net/http" | ||
"strings" | ||
"text/template" | ||
|
||
"github.com/prebid/openrtb/v20/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/macros" | ||
"github.com/prebid/prebid-server/v2/openrtb_ext" | ||
) | ||
|
||
type adapter struct { | ||
endpointTemplate *template.Template | ||
} | ||
|
||
// Builder builds a new instance of the {bidder} adapter for the given bidder with the given config. | ||
func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { | ||
template, err := template.New("endpointTemplate").Parse(config.Endpoint) | ||
if err != nil { | ||
return nil, fmt.Errorf("unable to parse endpoint url template: %v", err) | ||
} | ||
|
||
bidder := &adapter{ | ||
endpointTemplate: template, | ||
} | ||
|
||
return bidder, nil | ||
} | ||
|
||
func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { | ||
var requests []*adapters.RequestData | ||
var errors []error | ||
headers := http.Header{} | ||
headers.Add("Content-Type", "application/json;charset=utf-8") | ||
headers.Add("Accept", "application/json") | ||
|
||
requestCopy := *request | ||
for _, imp := range request.Imp { | ||
// Extract Melozen Params | ||
var strImpExt adapters.ExtImpBidder | ||
if err := json.Unmarshal(imp.Ext, &strImpExt); err != nil { | ||
errors = append(errors, err) | ||
continue | ||
} | ||
var strImpParams openrtb_ext.ImpExtMeloZen | ||
if err := json.Unmarshal(strImpExt.Bidder, &strImpParams); err != nil { | ||
errors = append(errors, err) | ||
continue | ||
} | ||
|
||
url, err := macros.ResolveMacros(a.endpointTemplate, macros.EndpointTemplateParams{PublisherID: strImpParams.PubId}) | ||
if err != nil { | ||
errors = append(errors, err) | ||
continue | ||
} | ||
// Convert Floor into USD | ||
if imp.BidFloor > 0 && imp.BidFloorCur != "" && !strings.EqualFold(imp.BidFloorCur, "USD") { | ||
convertedValue, err := reqInfo.ConvertCurrency(imp.BidFloor, imp.BidFloorCur, "USD") | ||
if err != nil { | ||
errors = append(errors, err) | ||
continue | ||
} | ||
imp.BidFloorCur = "USD" | ||
imp.BidFloor = convertedValue | ||
} | ||
|
||
impressionsByMediaType, err := splitImpressionsByMediaType(&imp) | ||
if err != nil { | ||
errors = append(errors, err) | ||
continue | ||
} | ||
|
||
for _, impression := range impressionsByMediaType { | ||
requestCopy.Imp = []openrtb2.Imp{impression} | ||
|
||
requestJSON, err := json.Marshal(requestCopy) | ||
if err != nil { | ||
errors = append(errors, err) | ||
continue | ||
} | ||
|
||
requestData := &adapters.RequestData{ | ||
Method: "POST", | ||
Uri: url, | ||
Body: requestJSON, | ||
Headers: headers, | ||
ImpIDs: openrtb_ext.GetImpIDs(requestCopy.Imp), | ||
} | ||
requests = append(requests, requestData) | ||
} | ||
} | ||
|
||
return requests, errors | ||
} | ||
|
||
func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) { | ||
if adapters.IsResponseStatusCodeNoContent(response) { | ||
return nil, nil | ||
} | ||
|
||
if err := adapters.CheckResponseStatusCodeForErrors(response); err != nil { | ||
return nil, []error{err} | ||
} | ||
|
||
var bidReq openrtb2.BidRequest | ||
if err := json.Unmarshal(requestData.Body, &bidReq); err != nil { | ||
return nil, []error{err} | ||
} | ||
|
||
var bidResp openrtb2.BidResponse | ||
if err := json.Unmarshal(response.Body, &bidResp); err != nil { | ||
return nil, []error{err} | ||
} | ||
|
||
bidderResponse := adapters.NewBidderResponse() | ||
var errors []error | ||
for _, seatBid := range bidResp.SeatBid { | ||
for i := range seatBid.Bid { | ||
bid := &seatBid.Bid[i] | ||
bidType, err := getMediaTypeForBid(*bid) | ||
if err != nil { | ||
errors = append(errors, err) | ||
continue | ||
} | ||
|
||
bidderResponse.Bids = append(bidderResponse.Bids, &adapters.TypedBid{ | ||
BidType: bidType, | ||
Bid: bid, | ||
}) | ||
} | ||
} | ||
return bidderResponse, errors | ||
} | ||
|
||
func splitImpressionsByMediaType(impression *openrtb2.Imp) ([]openrtb2.Imp, error) { | ||
if impression.Banner == nil && impression.Native == nil && impression.Video == nil { | ||
return nil, &errortypes.BadInput{Message: "Invalid MediaType. MeloZen only supports Banner, Video and Native."} | ||
onkarvhanumante marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
Comment on lines
+142
to
+144
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. as per should update bidder info yaml to support video media type or remove There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thank you for your feedback. I have updated the bidder-info/melozen.yaml file to reflect the correct media type support as suggested. The changes ensure that the video media type is appropriately handled. The updated configuration has been pushed to the PR. Please review the changes at your convenience. Thank you for guiding the improvements. |
||
|
||
impressions := make([]openrtb2.Imp, 0, 2) | ||
|
||
if impression.Banner != nil { | ||
impCopy := *impression | ||
impCopy.Video = nil | ||
impCopy.Native = nil | ||
impressions = append(impressions, impCopy) | ||
} | ||
|
||
if impression.Video != nil { | ||
impCopy := *impression | ||
impCopy.Banner = nil | ||
impCopy.Native = nil | ||
impressions = append(impressions, impCopy) | ||
} | ||
Comment on lines
+155
to
+160
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. as per should update bidder info yaml to support video media type or remove There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thank you for pointing out the need to align our code with the supported media types defined in bidder-info/melozen.yaml. I have updated the handling of media types within our adapter to ensure consistency with our declared capabilities. The changes have been made in the latest commit. Please review the updates and let me know if further adjustments are required. |
||
|
||
if impression.Native != nil { | ||
impCopy := *impression | ||
impCopy.Banner = nil | ||
impCopy.Video = nil | ||
impressions = append(impressions, impCopy) | ||
} | ||
|
||
return impressions, nil | ||
} | ||
|
||
func getMediaTypeForBid(bid openrtb2.Bid) (openrtb_ext.BidType, error) { | ||
|
||
if bid.Ext != nil { | ||
var bidExt openrtb_ext.ExtBid | ||
err := json.Unmarshal(bid.Ext, &bidExt) | ||
if err == nil && bidExt.Prebid != nil { | ||
return openrtb_ext.ParseBidType(string(bidExt.Prebid.Type)) | ||
onkarvhanumante marked this conversation as resolved.
Show resolved
Hide resolved
onkarvhanumante marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
} | ||
|
||
return "", &errortypes.BadServerResponse{ | ||
Message: fmt.Sprintf("Failed to parse bid mediatype for impression \"%s\"", bid.ImpID), | ||
} | ||
onkarvhanumante marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package melozen | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/prebid/prebid-server/v2/adapters/adapterstest" | ||
"github.com/prebid/prebid-server/v2/config" | ||
"github.com/prebid/prebid-server/v2/openrtb_ext" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestJsonSamples(t *testing.T) { | ||
|
||
bidder, buildErr := Builder(openrtb_ext.BidderMeloZen, config.Adapter{ | ||
Endpoint: "https://example.com/rtb/v2/bid?publisher_id={{.PublisherID}}", | ||
}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) | ||
|
||
if buildErr != nil { | ||
t.Fatalf("Builder returned unexpected error %v", buildErr) | ||
} | ||
|
||
adapterstest.RunJSONBidderTest(t, "melozentest", bidder) | ||
} | ||
|
||
func TestEndpointTemplateMalformed(t *testing.T) { | ||
_, buildErr := Builder(openrtb_ext.BidderMeloZen, config.Adapter{ | ||
Endpoint: "{{Malformed}}"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) | ||
|
||
assert.Error(t, buildErr) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
{ | ||
"mockBidRequest": { | ||
"id": "web-banner", | ||
"tmax": 3000, | ||
"imp": [ | ||
{ | ||
"id": "banner-imp-id", | ||
"ext": { | ||
"bidder": { | ||
"pubId": "386276e072" | ||
} | ||
}, | ||
"banner": { | ||
"format": [ | ||
{ | ||
"w": 300, | ||
"h": 250 | ||
} | ||
] | ||
} | ||
} | ||
], | ||
"app": { | ||
"bundle": "com.fake.app", | ||
"publisher": { | ||
"id": "42", | ||
"name": "whatever.pub" | ||
} | ||
}, | ||
"device": { | ||
"w": 1200, | ||
"h": 900 | ||
} | ||
}, | ||
"httpCalls": [ | ||
{ | ||
"expectedRequest": { | ||
"uri": "https://example.com/rtb/v2/bid?publisher_id=386276e072", | ||
"headers": { | ||
"Content-Type": ["application/json;charset=utf-8"], | ||
"Accept": ["application/json"] | ||
}, | ||
"body": { | ||
"id": "web-banner", | ||
"tmax": 3000, | ||
"imp": [ | ||
{ | ||
"id": "banner-imp-id", | ||
"ext": { | ||
"bidder": { | ||
"pubId": "386276e072" | ||
} | ||
}, | ||
"banner": { | ||
"format": [ | ||
{ | ||
"w": 300, | ||
"h": 250 | ||
} | ||
] | ||
} | ||
} | ||
], | ||
"device": { | ||
"w": 1200, | ||
"h": 900 | ||
}, | ||
"app": { | ||
"bundle": "com.fake.app", | ||
"publisher": { | ||
"id": "42", | ||
"name": "whatever.pub" | ||
} | ||
} | ||
}, | ||
"impIDs":["banner-imp-id"] | ||
}, | ||
"mockResponse": { | ||
"status": 200, | ||
"body": { | ||
"id": "web-banner", | ||
"cur": "USD", | ||
"seatbid": [ | ||
{ | ||
"bid": [ | ||
{ | ||
"id": "web-banner", | ||
"impid": "banner-imp-id", | ||
"crid": "some-creative-id", | ||
"adm": "<div>Ad</div>", | ||
"price": 20, | ||
"w": 300, | ||
"h": 250, | ||
"ext": { | ||
"prebid": { | ||
"type": "banner" | ||
} | ||
} | ||
} | ||
] | ||
} | ||
] | ||
} | ||
} | ||
} | ||
], | ||
"expectedBidResponses": [ | ||
{ | ||
"currency": "USD", | ||
"bids": [ | ||
{ | ||
"bid": { | ||
"id": "web-banner", | ||
"impid": "banner-imp-id", | ||
"crid": "some-creative-id", | ||
"adm": "<div>Ad</div>", | ||
"price": 20, | ||
"w": 300, | ||
"h": 250, | ||
"ext": { | ||
"prebid": { | ||
"type": "banner" | ||
} | ||
} | ||
}, | ||
"type": "banner" | ||
} | ||
] | ||
} | ||
] | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
replace
{bidder}
withmelozen
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for your helpful suggestion! I have updated the comment to specify "MeloZen" instead of "{bidder}" to clarify that this section is specifically designed for the MeloZen adapter. I appreciate your attention to detail and your patience as we refine the code. The updated comment has been pushed to the PR.