Skip to content

Commit

Permalink
DXKulture adapter (#3176)
Browse files Browse the repository at this point in the history
co-authored: @kmdevops
  • Loading branch information
bev-devops authored Oct 19, 2023
1 parent e8d93cc commit 34ddf1a
Show file tree
Hide file tree
Showing 20 changed files with 1,686 additions and 0 deletions.
170 changes: 170 additions & 0 deletions adapters/dxkulture/dxkulture.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
package dxkulture

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

"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"

"github.com/prebid/openrtb/v19/openrtb2"
)

var markupTypeToBidType = map[openrtb2.MarkupType]openrtb_ext.BidType{
openrtb2.MarkupBanner: openrtb_ext.BidTypeBanner,
openrtb2.MarkupVideo: openrtb_ext.BidTypeVideo,
}

type adapter struct {
endpoint string
}

// Builder builds a new instance of the DXKulture 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 := &adapter{
endpoint: config.Endpoint,
}
return bidder, nil
}

func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
impressions := request.Imp

adapterRequests := make([]*adapters.RequestData, 0, len(impressions))
var errs []error

for _, impression := range impressions {
impExt, err := parseExt(&impression)
if err != nil {
errs = append(errs, err)
continue
}

request.Imp = []openrtb2.Imp{impression}
body, err := json.Marshal(request)
if err != nil {
errs = append(errs, err)
continue
}

if request.Test == 1 {
impExt.PublisherId = "test"
}

params := url.Values{}
params.Add("publisher_id", impExt.PublisherId)
params.Add("placement_id", impExt.PlacementId)

adapterRequests = append(adapterRequests, &adapters.RequestData{
Method: http.MethodPost,
Uri: a.endpoint + "?" + params.Encode(),
Body: body,
Headers: getHeaders(request),
})
}

request.Imp = impressions
return adapterRequests, errs
}

func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *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 ortbResponse openrtb2.BidResponse
err := json.Unmarshal(response.Body, &ortbResponse)
if err != nil {
return nil, []error{&errortypes.BadServerResponse{
Message: "Bad Server Response",
}}
}

var bidErrors []error

bidderResponse := adapters.NewBidderResponseWithBidsCapacity(1)
for _, seatBid := range ortbResponse.SeatBid {
for i := range seatBid.Bid {
bid := seatBid.Bid[i]
bidType, err := getBidType(&bid)
if err != nil {
bidErrors = append(bidErrors, err)
continue
}

bidderResponse.Bids = append(bidderResponse.Bids, &adapters.TypedBid{
Bid: &bid,
BidType: bidType,
})
}
}

return bidderResponse, bidErrors
}

func getBidType(bid *openrtb2.Bid) (openrtb_ext.BidType, error) {
if bidType, ok := markupTypeToBidType[bid.MType]; ok {
return bidType, nil
}
return "", &errortypes.BadServerResponse{
Message: fmt.Sprintf("Unsupported MType %d", bid.MType),
}
}

func parseExt(imp *openrtb2.Imp) (*openrtb_ext.ExtImpDXKulture, error) {
var bidderExt adapters.ExtImpBidder

if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil {
return nil, &errortypes.BadInput{
Message: fmt.Sprintf("Ignoring imp id=%s, error while decoding extImpBidder, err: %s", imp.ID, err),
}
}

impExt := openrtb_ext.ExtImpDXKulture{}
err := json.Unmarshal(bidderExt.Bidder, &impExt)
if err != nil {
return nil, &errortypes.BadInput{
Message: fmt.Sprintf("Ignoring imp id=%s, error while decoding impExt, err: %s", imp.ID, err),
}
}

return &impExt, nil
}

func getHeaders(request *openrtb2.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.Site != nil {
if request.Site.Ref != "" {
headers.Set("Referer", request.Site.Ref)
}
if request.Site.Domain != "" {
headers.Add("Origin", request.Site.Domain)
}
}

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)
}
}
return headers
}
17 changes: 17 additions & 0 deletions adapters/dxkulture/dxkulture_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package dxkulture

import (
"testing"

"github.com/prebid/prebid-server/config"

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

func TestJsonSamples(t *testing.T) {
bidder, buildErr := Builder("dxkulture", config.Adapter{Endpoint: "https://ads.kulture.media/pbs"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"})
if buildErr != nil {
t.Fatalf("Builder returned unexpected error %v", buildErr)
}
adapterstest.RunJSONBidderTest(t, "dxkulturetest", bidder)
}
144 changes: 144 additions & 0 deletions adapters/dxkulture/dxkulturetest/exemplary/banner.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
{
"mockBidRequest": {
"id": "test-request-id",
"user": {
"buyeruid": "userId",
"yob": 1990
},
"device": {
"ua": "user-agent",
"ip": "1.2.3.4"
},
"imp": [
{
"id": "test-imp-id",
"banner": {
"w": 300,
"h": 250
},
"ext": {
"bidder": {
"publisherId": "pub123",
"placementId": "placement123"
}
}
}
],
"site": {
"domain": "site.com",
"page": "http://site.com/page",
"ref": "http://site.com/ref"
}
},
"httpCalls": [
{
"expectedRequest": {
"method": "GET",
"headers": {
"Referer": [
"http://site.com/ref"
],
"Origin": [
"site.com"
],
"Accept": [
"application/json"
],
"Content-Type": [
"application/json;charset=utf-8"
],
"User-Agent": [
"user-agent"
],
"X-Forwarded-For": [
"1.2.3.4"
],
"X-Openrtb-Version": [
"2.5"
]
},
"uri": "https://ads.kulture.media/pbs?placement_id=placement123&publisher_id=pub123",
"body": {
"id": "test-request-id",
"user": {
"buyeruid": "userId",
"yob": 1990
},
"device": {
"ua": "user-agent",
"ip": "1.2.3.4"
},
"imp": [
{
"id": "test-imp-id",
"banner": {
"w": 300,
"h": 250
},
"ext": {
"bidder": {
"publisherId": "pub123",
"placementId": "placement123"
}
}
}
],
"site": {
"domain": "site.com",
"page": "http://site.com/page",
"ref": "http://site.com/ref"
}
}
},
"mockResponse": {
"status": 200,
"body": {
"cur": "USD",
"seatbid": [
{
"bid": [
{
"id": "43271b2d-41c0-4093-8ba1-2105d9658e80",
"crid": "16329",
"adomain": [
"adomain.com"
],
"price": 3,
"impid": "test-imp-id",
"adid": "2422",
"adm": "<iframe width=\"300\" height=\"250\"></iframe>",
"mtype": 1
}
],
"seat": "dxkulture"
}
],
"bidid": "test-request-id",
"id": "test-request-id"
}
}
}
],
"expectedBidResponses": [
{
"currency": "USD",
"bids": [
{
"bid": {
"id": "43271b2d-41c0-4093-8ba1-2105d9658e80",
"crid": "16329",
"adomain": [
"adomain.com"
],
"price": 3,
"impid": "test-imp-id",
"adid": "2422",
"adm": "<iframe width=\"300\" height=\"250\"></iframe>",
"mtype": 1
},
"type": "banner"
}
]
}
]
}
Loading

0 comments on commit 34ddf1a

Please sign in to comment.