Skip to content

Commit

Permalink
New Adapter: Missena
Browse files Browse the repository at this point in the history
  • Loading branch information
ysfbsf committed Jun 18, 2024
1 parent 4dc4005 commit 4d210b9
Show file tree
Hide file tree
Showing 14 changed files with 756 additions and 0 deletions.
226 changes: 226 additions & 0 deletions adapters/missena/missena.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
package missena

import (
"encoding/json"
"fmt"
"net/http"
"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/openrtb_ext"
)

type adapter struct {
endpoint string
}

type MissenaAdRequest struct {
RequestId string `json:"request_id"`
Timeout int `json:"timeout"`
Referer string `json:"referer"`
RefererCanonical string `json:"referer_canonical"`
GDPRConsent string `json:"consent_string"`
GDPR bool `json:"consent_required"`
Placement string `json:"placement"`
TestMode string `json:"test"`
}

type MissenaBidServerResponse struct {
Ad string `json:"ad"`
Cpm float64 `json:"cpm"`
Currency string `json:"currency"`
RequestId string `json:"requestId"`
}

type MissenaInternalParams struct {
ApiKey string
RequestId string
Timeout int
Referer string
RefererCanonical string
GDPRConsent string
GDPR bool
Placement string
TestMode string
}

type MissenaAdapter struct {
EndpointTemplate *template.Template
}

// Builder builds a new instance of the Foo 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) makeParameter(missenaParams MissenaInternalParams, request *openrtb2.BidRequest) *MissenaAdRequest {
missenaRequest := MissenaAdRequest{
RequestId: request.ID,
Timeout: 2000,
Referer: request.Site.Page,
RefererCanonical: request.Site.Domain,
GDPRConsent: missenaParams.GDPRConsent,
GDPR: missenaParams.GDPR,
Placement: missenaParams.Placement,
TestMode: missenaParams.TestMode,
}
return &missenaRequest
}

func (a *adapter) makeRequest(missenaParams MissenaInternalParams, reqInfo *adapters.ExtraRequestInfo, existingRequests []*adapters.RequestData, request *openrtb2.BidRequest) (*adapters.RequestData, error) {

url := a.endpoint + "?t=" + missenaParams.ApiKey
parameter := a.makeParameter(missenaParams, request)
body, errm := json.Marshal(parameter)
if errm != nil {
return nil, errm
}

headers := http.Header{}
headers.Add("Content-Type", "application/json;charset=utf-8")
headers.Add("Accept", "application/json")

if request.Device != nil {
headers.Add("User-Agent", request.Device.UA)
}

if request.Device != nil {
if request.Device.IP != "" {
headers.Add("X-Forwarded-For", request.Device.IP)
} else if request.Device.IPv6 != "" {
headers.Add("X-Forwarded-For", request.Device.IPv6)
}
}
if request.Site != nil {
headers.Add("Referer", request.Site.Page)
}

return &adapters.RequestData{
Method: "POST",
Uri: url,
Headers: headers,
Body: body,
ImpIDs: openrtb_ext.GetImpIDs(request.Imp),
}, nil
}

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

var httpRequests []*adapters.RequestData
var tempErrors []error
gdprApplies, consentString := readGDPR(request)

var missenaInternalParams MissenaInternalParams

for _, imp := range request.Imp {
var bidderExt adapters.ExtImpBidder
if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil {
tempErrors = append(tempErrors, &errortypes.BadInput{
Message: "Error parsing bidderExt object",
})
continue
}

var missenaExt openrtb_ext.ExtImpMissena
if err := json.Unmarshal(bidderExt.Bidder, &missenaExt); err != nil {
tempErrors = append(tempErrors, &errortypes.BadInput{
Message: "Error parsing missenaExt parameters",
})
continue
}

missenaInternalParams.ApiKey = missenaExt.ApiKey
missenaInternalParams.Placement = missenaExt.Placement
missenaInternalParams.TestMode = missenaExt.TestMode
}

var finalErrors []error
missenaInternalParams.GDPR = gdprApplies
missenaInternalParams.GDPRConsent = consentString

newHttpRequest, err := a.makeRequest(missenaInternalParams, requestInfo, httpRequests, request)

if len(tempErrors) > 0 {
return nil, tempErrors
}

if err != nil {
finalErrors = append(finalErrors, err)
} else if newHttpRequest != nil {
httpRequests = append(httpRequests, newHttpRequest)
}

return httpRequests, finalErrors
}

func readGDPR(request *openrtb2.BidRequest) (bool, string) {
consentString := ""
if request.User != nil {
var extUser openrtb_ext.ExtUser
if err := json.Unmarshal(request.User.Ext, &extUser); err == nil {
consentString = extUser.Consent
}
}
gdprApplies := true
var extRegs openrtb_ext.ExtRegs
if request.Regs != nil {
if err := json.Unmarshal(request.Regs.Ext, &extRegs); err == nil {
if extRegs.GDPR != nil {
gdprApplies = (*extRegs.GDPR == 1)
}
}
}
return gdprApplies, consentString
}

func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) {
if responseData.StatusCode == http.StatusNoContent {
return nil, nil
}

if responseData.StatusCode == http.StatusBadRequest {
err := &errortypes.BadInput{
Message: "Unexpected status code: 400. Bad request from publisher. Run with request.debug = 1 for more info.",
}
return nil, []error{err}
}

if responseData.StatusCode != http.StatusOK {
err := &errortypes.BadServerResponse{
Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info.", responseData.StatusCode),
}
return nil, []error{err}
}

var missenaResponse MissenaBidServerResponse
if err := json.Unmarshal(responseData.Body, &missenaResponse); err != nil {
return nil, []error{err}
}

bidResponse := adapters.NewBidderResponseWithBidsCapacity(1)
bidResponse.Currency = missenaResponse.Currency

responseBid := &openrtb2.Bid{
ID: request.ID,
Price: float64(missenaResponse.Cpm),
ImpID: request.Imp[0].ID,
AdM: missenaResponse.Ad,
CrID: missenaResponse.RequestId,
}

b := &adapters.TypedBid{
Bid: responseBid,
BidType: openrtb_ext.BidTypeBanner,
}

bidResponse.Bids = append(bidResponse.Bids, b)

var errors []error
return bidResponse, errors
}
21 changes: 21 additions & 0 deletions adapters/missena/missena_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package missena

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

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

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

adapterstest.RunJSONBidderTest(t, "missenatest", bidder)
}
105 changes: 105 additions & 0 deletions adapters/missena/missenatest/exemplary/simple-banner.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
{
"mockBidRequest": {
"id": "test-request-id",
"tmax": 500,
"at": 1,
"cur": [
"EUR"
],
"regs": {
"ext": {
"gdpr": 1
}
},
"user": {
"ext": {
"consent": "CO-X2XiO_eyUoAsAxBFRBECsA"
}
},
"device": {
"ip": "123.123.123.123",
"ua": "test-user-agent"
},
"site": {
"page": "https://example.com/page",
"domain": "example.com"
},
"imp": [
{
"id": "test-imp-id",
"banner": {
"h": 50,
"w": 320
},
"ext": {
"bidder": {
"apiKey": "test-api-key",
"placement": "test-placement",
"test": "1"
}
}
}
]
},
"httpCalls": [
{
"expectedRequest": {
"uri": "https://bid.missena.io?t=test-api-key",
"headers": {
"Content-Type": [
"application/json;charset=utf-8"
],
"Accept": [
"application/json"
],
"User-Agent": [
"test-user-agent"
],
"X-Forwarded-For": [
"123.123.123.123"
],
"Referer": [
"https://example.com/page"
]
},
"body": {
"request_id": "test-request-id",
"timeout": 2000,
"referer": "https://example.com/page",
"referer_canonical": "example.com",
"consent_string": "CO-X2XiO_eyUoAsAxBFRBECsA",
"consent_required": true,
"placement": "test-placement",
"test": "1"
},
"impIDs":["test-imp-id"]
},
"mockResponse": {
"status": 200,
"body": {
"ad": "<div>test ad</div>",
"cpm": 1.5,
"currency": "EUR",
"requestId": "test-request-id"
}
}
}
],
"expectedBidResponses": [
{
"currency": "EUR",
"bids": [
{
"bid": {
"id": "test-request-id",
"impid": "test-imp-id",
"price": 1.5,
"adm": "<div>test ad</div>",
"crid": "test-request-id"
},
"type": "banner"
}
]
}
]
}
25 changes: 25 additions & 0 deletions adapters/missena/missenatest/supplemental/error-ext-bidder.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"mockBidRequest": {
"id": "test-request-id",
"site": {
"page": "https://publisher.com/url"
},
"user": {
"buyeruid": "1"
},
"imp": [
{
"id": "test-imp-id",
"ext": {
"bidder": "abc"
}
}
]
},
"expectedMakeRequestsErrors": [
{
"value": "Error parsing missenaExt parameters",
"comparison": "literal"
}
]
}
Loading

0 comments on commit 4d210b9

Please sign in to comment.