Skip to content
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

Districtm Dmx: new adapter #1209

Merged
merged 47 commits into from
Jun 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
0d36837
Merge pull request #1 from prebid/master
stevealliance Nov 21, 2019
a098d7c
adding DMX main file
steve-a-districtm Mar 2, 2020
255d384
adding user sync for dmx
steve-a-districtm Mar 2, 2020
c78cdcc
adding dmx in the adapter map
steve-a-districtm Mar 2, 2020
436f3a5
mapping in struct Adapter 'publisherId'
steve-a-districtm Mar 2, 2020
49bcf69
adding config in syncer.go
steve-a-districtm Mar 2, 2020
419bfc6
set config endpoint for dmx
steve-a-districtm Mar 2, 2020
f04450f
set default usersync url template
steve-a-districtm Mar 2, 2020
b3e6fbc
adding dmx to bidder.go
steve-a-districtm Mar 2, 2020
0f4e542
adding user sync test
steve-a-districtm Mar 2, 2020
08f108d
adding json bidder params
steve-a-districtm Mar 2, 2020
afb9768
adding yaml file
steve-a-districtm Mar 2, 2020
bd77380
remove fmt.Println
steve-a-districtm Mar 2, 2020
8e27b0b
adding media types app banner
steve-a-districtm Mar 2, 2020
63b61d2
adding DMX into sync test
steve-a-districtm Mar 2, 2020
572cc96
update correction required plus unit test
steve-a-districtm Mar 23, 2020
8bc4bd2
run gofmt on dmx
steve-a-districtm Mar 24, 2020
4e41153
update sellerid support in params
steve-a-districtm Apr 6, 2020
a00c90c
change setup key form publisherId to sellerId
steve-a-districtm Apr 6, 2020
9e4693d
update bidder info to main districtm mailbox
steve-a-districtm Apr 15, 2020
b53697a
run gofmt on bidders.go
steve-a-districtm Apr 15, 2020
b6530cb
update unit test to reflect change on main dmx.go
steve-a-districtm Apr 15, 2020
311e106
remove config setting inside config.go | run fmt
steve-a-districtm Apr 15, 2020
aa1dd6e
syncer_test.go update
steve-a-districtm Apr 15, 2020
465ab83
add test to confirm that site doesn't generate a panic in go
steve-a-districtm Apr 16, 2020
f906587
update request from last review (PR)
steve-a-districtm Apr 16, 2020
31d3f0b
update dmx.yaml file for video support
steve-a-districtm Apr 20, 2020
5f0339e
update support for video + testing at 88% coverage
steve-a-districtm Apr 21, 2020
3dcb2dc
update code based on last comment
steve-a-districtm Apr 22, 2020
30c595d
update idsync endpoint
steve-a-districtm Apr 22, 2020
409caec
update fetchparams to append nothing when tagid || dmxid is empty
steve-a-districtm Apr 22, 2020
f655384
Eids and Digitrust validation
steve-a-districtm Apr 23, 2020
c3f6364
create a full new instance of the App Site User value
steve-a-districtm Apr 30, 2020
c851a32
adding support for test exemplary and race
steve-a-districtm May 11, 2020
d7bb136
publisher share memory fix
steve-a-districtm May 11, 2020
9e6fe59
code removed
steve-a-districtm May 11, 2020
711e779
adding Digitrust verification 'nil'
steve-a-districtm May 12, 2020
cbbd517
update the test with empty user.ext
steve-a-districtm May 13, 2020
2b82610
remove deep copy function for performance issue
steve-a-districtm May 18, 2020
e649de1
remove custom struct for userExt
steve-a-districtm May 19, 2020
4bf0745
inforced dmxReq to be a pointer
steve-a-districtm May 27, 2020
0284310
Merge remote-tracking branch 'upstream/master'
steve-a-districtm May 29, 2020
8ed9ec3
fix code conflict for adapter_map.go
steve-a-districtm May 29, 2020
b6ed6da
update master branch to reflect code in forked master
steve-a-districtm Jun 2, 2020
2f3c122
fix conflict
stevealliance Jun 2, 2020
76372d0
Merge pull request #5 from stevealliance/fix-branch
stevealliance Jun 2, 2020
a4ac24f
update latest change for GDPR CCPA
stevealliance Jun 3, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
296 changes: 296 additions & 0 deletions adapters/dmx/dmx.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,296 @@
package dmx

import (
"encoding/json"
"errors"
"fmt"
"github.com/mxmCherry/openrtb"
"github.com/prebid/prebid-server/adapters"
"github.com/prebid/prebid-server/errortypes"
"github.com/prebid/prebid-server/openrtb_ext"
"net/http"
"net/url"
"strings"
)

type DmxAdapter struct {
stevealliance marked this conversation as resolved.
Show resolved Hide resolved
endpoint string
}

func NewDmxBidder(endpoint string) *DmxAdapter {
return &DmxAdapter{endpoint: endpoint}
}

type dmxExt struct {
Bidder dmxParams `json:"bidder"`
}

type dmxParams struct {
TagId string `json:"tagid,omitempty"`
DmxId string `json:"dmxid,omitempty"`
MemberId string `json:"memberid,omitempty"`
PublisherId string `json:"publisher_id,omitempty"`
SellerId string `json:"seller_id,omitempty"`
}

func UserSellerOrPubId(str1, str2 string) string {
if str1 != "" {
return str1
}
return str2
}

func (adapter *DmxAdapter) MakeRequests(request *openrtb.BidRequest, req *adapters.ExtraRequestInfo) (reqsBidder []*adapters.RequestData, errs []error) {
var imps []openrtb.Imp
var rootExtInfo dmxExt
var publisherId string
var sellerId string
var userExt openrtb_ext.ExtUser
var anyHasId = false
var reqCopy openrtb.BidRequest = *request
var dmxReq *openrtb.BidRequest = &reqCopy

if request.User == nil {
if request.App == nil {
return nil, []error{errors.New("No user id or app id found. Could not send request to DMX.")}
}
}

if len(request.Imp) >= 1 {
stevealliance marked this conversation as resolved.
Show resolved Hide resolved
err := json.Unmarshal(request.Imp[0].Ext, &rootExtInfo)
if err != nil {
errs = append(errs, err)
} else {
publisherId = UserSellerOrPubId(rootExtInfo.Bidder.PublisherId, rootExtInfo.Bidder.MemberId)
sellerId = rootExtInfo.Bidder.SellerId
}
}

if request.App != nil {
appCopy := *request.App
appPublisherCopy := *request.App.Publisher
dmxReq.App = &appCopy
dmxReq.App.Publisher = &appPublisherCopy
if dmxReq.App.ID != "" {
anyHasId = true
}
} else {
dmxReq.App = nil
}

if request.Site != nil {
siteCopy := *request.Site
sitePublisherCopy := *request.Site.Publisher
dmxReq.Site = &siteCopy
dmxReq.Site.Publisher = &sitePublisherCopy
if dmxReq.Site.Publisher != nil {
dmxReq.Site.Publisher.ID = publisherId
} else {
dmxReq.Site.Publisher = &openrtb.Publisher{ID: publisherId}
}
} else {
dmxReq.Site = nil
}

if request.User != nil {
userCopy := *request.User
dmxReq.User = &userCopy
} else {
dmxReq.User = nil
}

if dmxReq.User != nil {
if dmxReq.User.ID != "" {
anyHasId = true
}
if dmxReq.User.Ext != nil {
if err := json.Unmarshal(dmxReq.User.Ext, &userExt); err == nil {
if len(userExt.Eids) > 0 || (userExt.DigiTrust != nil && userExt.DigiTrust.ID != "") {
anyHasId = true
}
}
}
}

if anyHasId == false {
return nil, []error{errors.New("This request contained no identifier")}
}

for _, inst := range dmxReq.Imp {
var banner *openrtb.Banner
var video *openrtb.Video
var ins openrtb.Imp
var params dmxExt
const intVal int8 = 1
source := (*json.RawMessage)(&inst.Ext)
if err := json.Unmarshal(*source, &params); err != nil {
errs = append(errs, err)
}
if isDmxParams(params.Bidder) {
if inst.Banner != nil {
if len(inst.Banner.Format) != 0 {
banner = inst.Banner
if params.Bidder.PublisherId != "" || params.Bidder.MemberId != "" {
imps = fetchParams(params, inst, ins, imps, banner, nil, intVal)
} else {
return nil, []error{errors.New("Missing Params for auction to be send")}
}
}
}

if inst.Video != nil {
video = inst.Video
if params.Bidder.PublisherId != "" || params.Bidder.MemberId != "" {
imps = fetchParams(params, inst, ins, imps, nil, video, intVal)
} else {
return nil, []error{errors.New("Missing Params for auction to be send")}
}
}
}

}

dmxReq.Imp = imps

oJson, err := json.Marshal(dmxReq)

if err != nil {
errs = append(errs, err)
stevealliance marked this conversation as resolved.
Show resolved Hide resolved
return nil, errs
}

headers := http.Header{}
headers.Add("Content-Type", "Application/json;charset=utf-8")
reqBidder := &adapters.RequestData{
Method: "POST",
Uri: adapter.endpoint + addParams(sellerId), //adapter.endpoint,
Body: oJson,
Headers: headers,
}
reqsBidder = append(reqsBidder, reqBidder)
return
}

func (adapter *DmxAdapter) MakeBids(request *openrtb.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) {
var errs []error

if http.StatusNoContent == response.StatusCode {
stevealliance marked this conversation as resolved.
Show resolved Hide resolved
return nil, nil
}

if http.StatusBadRequest == response.StatusCode {
return nil, []error{&errortypes.BadInput{
Message: fmt.Sprintf("Unexpected status code 400"),
}}
}

if http.StatusOK != response.StatusCode {
return nil, []error{&errortypes.BadInput{
Message: fmt.Sprintf("Unexpected response no status code"),
}}
}

var bidResp openrtb.BidResponse

if err := json.Unmarshal(response.Body, &bidResp); err != nil {
return nil, []error{err}
}

bidResponse := adapters.NewBidderResponseWithBidsCapacity(5)

for _, sb := range bidResp.SeatBid {
for i := range sb.Bid {
bidType, err := getMediaTypeForImp(sb.Bid[i].ImpID, request.Imp)
if err != nil {
errs = append(errs, err)
} else {
b := &adapters.TypedBid{
Bid: &sb.Bid[i],
BidType: bidType,
}
if b.BidType == openrtb_ext.BidTypeVideo {
b.Bid.AdM = videoImpInsertion(b.Bid)
}
bidResponse.Bids = append(bidResponse.Bids, b)
}
}
}
return bidResponse, errs

}

func fetchParams(params dmxExt, inst openrtb.Imp, ins openrtb.Imp, imps []openrtb.Imp, banner *openrtb.Banner, video *openrtb.Video, intVal int8) []openrtb.Imp {
if params.Bidder.TagId != "" {
ins = openrtb.Imp{
ID: inst.ID,
TagID: params.Bidder.TagId,
Ext: inst.Ext,
Secure: &intVal,
}
}

if params.Bidder.DmxId != "" {
ins = openrtb.Imp{
ID: inst.ID,
TagID: params.Bidder.DmxId,
Ext: inst.Ext,
Secure: &intVal,
}
}
if banner != nil {
ins.Banner = banner
}

if video != nil {
ins.Video = video
}

if ins.TagID == "" {
return imps
}
imps = append(imps, ins)
stevealliance marked this conversation as resolved.
Show resolved Hide resolved
return imps
}

func addParams(str string) string {
if str != "" {
return "?sellerid=" + url.QueryEscape(str)
}
return ""
}

func getMediaTypeForImp(impID string, imps []openrtb.Imp) (openrtb_ext.BidType, error) {
mediaType := openrtb_ext.BidTypeBanner
for _, imp := range imps {
if imp.ID == impID {
if imp.Banner == nil && imp.Video != nil {
mediaType = openrtb_ext.BidTypeVideo
}
return mediaType, nil
}
}

// This shouldnt happen. Lets handle it just incase by returning an error.
return "", &errortypes.BadInput{
Message: fmt.Sprintf("Failed to find impression \"%s\" ", impID),
}
}

func videoImpInsertion(bid *openrtb.Bid) string {
adm := bid.AdM
nurl := bid.NURL
search := "</Impression>"
imp := "</Impression><Impression><![CDATA[%s]]></Impression>"
wrapped_nurl := fmt.Sprintf(imp, nurl)
results := strings.Replace(adm, search, wrapped_nurl, 1)
return results
}

func isDmxParams(t interface{}) bool {
switch t.(type) {
case dmxParams:
return true
default:
return false
}
}
Loading