Skip to content

Commit fcf5706

Browse files
authored
add ttd (#80)
1 parent 4fec088 commit fcf5706

File tree

14 files changed

+310
-16
lines changed

14 files changed

+310
-16
lines changed

.github/workflows/security.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ on:
1111
jobs:
1212
build:
1313
name: Trivy
14-
runs-on: ubuntu-20.04
14+
runs-on: ubuntu-latest
1515
steps:
1616
- name: Checkout Code
1717
uses: actions/checkout@v3
@@ -31,4 +31,4 @@ jobs:
3131
- name: Upload Results To GitHub Security Tab
3232
uses: github/codeql-action/upload-sarif@v2
3333
with:
34-
sarif_file: 'trivy-results.sarif'
34+
sarif_file: 'trivy-results.sarif'

.github/workflows/validate-merge.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ on:
66

77
jobs:
88
validate-merge:
9-
runs-on: ubuntu-20.04
9+
runs-on: ubuntu-latest
1010

1111
steps:
1212
- name: Install Go

.github/workflows/validate.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ jobs:
1111
strategy:
1212
matrix:
1313
go-version: [1.18.x, 1.19.x]
14-
os: [ubuntu-20.04]
14+
os: [ubuntu-latest]
1515
runs-on: ${{ matrix.os }}
1616

1717
steps:

adapters/bidder.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ type RequestData struct {
122122
Uri string
123123
Body []byte
124124
Headers http.Header
125+
ImpIDs []string
125126
}
126127

127128
// ExtImpBidder can be used by Bidders to unmarshal any request.imp[i].ext.
Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
package thetradedesk
2+
3+
import (
4+
"encoding/json"
5+
"errors"
6+
"fmt"
7+
"net/http"
8+
"regexp"
9+
"text/template"
10+
11+
"github.com/prebid/prebid-server/adapters"
12+
"github.com/prebid/prebid-server/config"
13+
"github.com/prebid/prebid-server/macros"
14+
"github.com/prebid/prebid-server/openrtb_ext"
15+
16+
"github.com/prebid/openrtb/v19/openrtb2"
17+
)
18+
19+
//const PREBID_INTEGRATION_TYPE = "1"
20+
21+
type adapter struct {
22+
bidderEndpointTemplate string
23+
defaultEndpoint string
24+
templateEndpoint *template.Template
25+
}
26+
27+
func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
28+
pubID, supplySourceId, err := getExtensionInfo(request.Imp)
29+
30+
if err != nil {
31+
return nil, []error{err}
32+
}
33+
34+
modifiedImps := make([]openrtb2.Imp, 0, len(request.Imp))
35+
36+
for _, imp := range request.Imp {
37+
38+
if imp.Banner != nil {
39+
if len(imp.Banner.Format) > 0 {
40+
firstFormat := imp.Banner.Format[0]
41+
bannerCopy := *imp.Banner
42+
bannerCopy.H = &firstFormat.H
43+
bannerCopy.W = &firstFormat.W
44+
imp.Banner = &bannerCopy
45+
46+
}
47+
}
48+
49+
modifiedImps = append(modifiedImps, imp)
50+
}
51+
52+
request.Imp = modifiedImps
53+
54+
if request.Site != nil {
55+
siteCopy := *request.Site
56+
if siteCopy.Publisher != nil {
57+
publisherCopy := *siteCopy.Publisher
58+
if pubID != "" {
59+
publisherCopy.ID = pubID
60+
}
61+
siteCopy.Publisher = &publisherCopy
62+
} else {
63+
siteCopy.Publisher = &openrtb2.Publisher{ID: pubID}
64+
}
65+
request.Site = &siteCopy
66+
} else if request.App != nil {
67+
appCopy := *request.App
68+
if appCopy.Publisher != nil {
69+
publisherCopy := *appCopy.Publisher
70+
if pubID != "" {
71+
publisherCopy.ID = pubID
72+
}
73+
appCopy.Publisher = &publisherCopy
74+
} else {
75+
appCopy.Publisher = &openrtb2.Publisher{ID: pubID}
76+
}
77+
request.App = &appCopy
78+
}
79+
80+
errs := make([]error, 0, len(request.Imp))
81+
reqJSON, err := json.Marshal(request)
82+
if err != nil {
83+
errs = append(errs, err)
84+
return nil, errs
85+
}
86+
87+
bidderEndpoint, err := a.buildEndpointURL(supplySourceId)
88+
if err != nil {
89+
return nil, []error{errors.New("Failed to build endpoint URL")}
90+
}
91+
92+
headers := http.Header{}
93+
headers.Add("Content-Type", "application/json;charset=utf-8")
94+
headers.Add("Accept", "application/json")
95+
//headers.Add("x-integration-type", PREBID_INTEGRATION_TYPE) this will be parsed and added conditionally later
96+
return []*adapters.RequestData{{
97+
Method: "POST",
98+
Uri: bidderEndpoint,
99+
Body: reqJSON,
100+
Headers: headers,
101+
ImpIDs: openrtb_ext.GetImpIDs(request.Imp),
102+
}}, errs
103+
}
104+
105+
func (a *adapter) buildEndpointURL(supplySourceId string) (string, error) {
106+
if supplySourceId == "" {
107+
return a.defaultEndpoint, nil
108+
}
109+
110+
urlParams := macros.EndpointTemplateParams{SupplyId: supplySourceId}
111+
bidderEndpoint, err := macros.ResolveMacros(a.templateEndpoint, urlParams)
112+
113+
if err != nil {
114+
return "", fmt.Errorf("unable to resolve endpoint macros: %v", err)
115+
}
116+
117+
return bidderEndpoint, nil
118+
}
119+
120+
func getExtensionInfo(impressions []openrtb2.Imp) (string, string, error) {
121+
publisherId := ""
122+
supplySourceId := ""
123+
for _, imp := range impressions {
124+
var ttdExt, err = getImpressionExt(&imp)
125+
if err != nil {
126+
return "", "", err
127+
}
128+
129+
if ttdExt.PublisherId != "" && publisherId == "" {
130+
publisherId = ttdExt.PublisherId
131+
}
132+
133+
if ttdExt.SupplySourceId != "" && supplySourceId == "" {
134+
supplySourceId = ttdExt.SupplySourceId
135+
}
136+
137+
if publisherId != "" && supplySourceId != "" {
138+
break
139+
}
140+
}
141+
return publisherId, supplySourceId, nil
142+
}
143+
144+
func getImpressionExt(imp *openrtb2.Imp) (*openrtb_ext.ExtImpTheTradeDesk, error) {
145+
var bidderExt adapters.ExtImpBidder
146+
if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil {
147+
return nil, err
148+
}
149+
150+
var ttdExt openrtb_ext.ExtImpTheTradeDesk
151+
if err := json.Unmarshal(bidderExt.Bidder, &ttdExt); err != nil {
152+
return nil, err
153+
}
154+
return &ttdExt, nil
155+
}
156+
157+
func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) {
158+
if adapters.IsResponseStatusCodeNoContent(response) {
159+
return adapters.NewBidderResponse(), nil
160+
}
161+
162+
if err := adapters.CheckResponseStatusCodeForErrors(response); err != nil {
163+
return nil, []error{err}
164+
}
165+
166+
var bidResponse openrtb2.BidResponse
167+
if err := json.Unmarshal(response.Body, &bidResponse); err != nil {
168+
return nil, []error{err}
169+
}
170+
171+
bidderResponse := adapters.NewBidderResponse()
172+
bidderResponse.Currency = bidResponse.Cur
173+
174+
for _, seatBid := range bidResponse.SeatBid {
175+
for _, bid := range seatBid.Bid {
176+
bid := bid
177+
178+
bidType, err := getBidType(bid.MType)
179+
180+
if err != nil {
181+
return nil, []error{err}
182+
}
183+
184+
b := &adapters.TypedBid{
185+
Bid: &bid,
186+
BidType: bidType,
187+
}
188+
bidderResponse.Bids = append(bidderResponse.Bids, b)
189+
}
190+
}
191+
192+
return bidderResponse, nil
193+
}
194+
195+
func getBidType(markupType openrtb2.MarkupType) (openrtb_ext.BidType, error) {
196+
switch markupType {
197+
case openrtb2.MarkupBanner:
198+
return openrtb_ext.BidTypeBanner, nil
199+
case openrtb2.MarkupVideo:
200+
return openrtb_ext.BidTypeVideo, nil
201+
case openrtb2.MarkupNative:
202+
return openrtb_ext.BidTypeNative, nil
203+
default:
204+
return "", fmt.Errorf("unsupported mtype: %d", markupType)
205+
}
206+
}
207+
208+
func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) {
209+
if len(config.ExtraAdapterInfo) > 0 {
210+
isValidEndpoint, err := regexp.Match("([a-z]+)$", []byte(config.ExtraAdapterInfo))
211+
if !isValidEndpoint || err != nil {
212+
return nil, errors.New("ExtraAdapterInfo must be a simple string provided by TheTradeDesk")
213+
}
214+
}
215+
216+
template, err := template.New("endpointTemplate").Parse(config.Endpoint)
217+
if err != nil {
218+
return nil, fmt.Errorf("unable to parse endpoint url template: %v", err)
219+
}
220+
221+
urlParams := macros.EndpointTemplateParams{SupplyId: config.ExtraAdapterInfo}
222+
defaultEndpoint, err := macros.ResolveMacros(template, urlParams)
223+
224+
if err != nil {
225+
return nil, fmt.Errorf("unable to resolve endpoint macros: %v", err)
226+
}
227+
228+
return &adapter{
229+
bidderEndpointTemplate: config.Endpoint,
230+
defaultEndpoint: defaultEndpoint,
231+
templateEndpoint: template,
232+
}, nil
233+
}

exchange/adapter_builders.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ import (
157157
"github.com/prebid/prebid-server/adapters/taboola"
158158
"github.com/prebid/prebid-server/adapters/tappx"
159159
"github.com/prebid/prebid-server/adapters/telaria"
160+
"github.com/prebid/prebid-server/adapters/thetradedesk"
160161
"github.com/prebid/prebid-server/adapters/trafficgate"
161162
"github.com/prebid/prebid-server/adapters/triplelift"
162163
"github.com/prebid/prebid-server/adapters/triplelift_native"
@@ -311,6 +312,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder {
311312
openrtb_ext.BidderMobileFuse: mobilefuse.Builder,
312313
openrtb_ext.BidderMotorik: motorik.Builder,
313314
openrtb_ext.BidderNativo: nativo.Builder,
315+
openrtb_ext.BidderTheTradeDesk: thetradedesk.Builder,
314316
openrtb_ext.BidderNanoInteractive: nanointeractive.Builder,
315317
openrtb_ext.BidderNextMillennium: nextmillennium.Builder,
316318
openrtb_ext.BidderNinthDecimal: ninthdecimal.Builder,

macros/macros.go

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import (
55
"text/template"
66
)
77

8-
// EndpointTemplateParams specifies params for an endpoint template
8+
// EndpointTemplateParams specifies macros for bidder endpoints.
99
type EndpointTemplateParams struct {
1010
Host string
1111
PublisherID string
@@ -15,10 +15,17 @@ type EndpointTemplateParams struct {
1515
AdUnit string
1616
MediaType string
1717
GvlID string
18+
PageID string
19+
SupplyId string
20+
ImpID string
21+
SspId string
22+
SspID string
23+
SeatID string
24+
TokenID string
1825
}
1926

20-
// UserSyncTemplateParams specifies params for an user sync URL template
21-
type UserSyncTemplateParams struct {
27+
// UserSyncPrivacy specifies privacy policy macros, represented as strings, for user sync urls.
28+
type UserSyncPrivacy struct {
2229
GDPR string
2330
GDPRConsent string
2431
USPrivacy string
@@ -30,10 +37,10 @@ type UserSyncTemplateParams struct {
3037
func ResolveMacros(aTemplate *template.Template, params interface{}) (string, error) {
3138
strBuf := bytes.Buffer{}
3239

33-
err := aTemplate.Execute(&strBuf, params)
34-
if err != nil {
40+
if err := aTemplate.Execute(&strBuf, params); err != nil {
3541
return "", err
3642
}
43+
3744
res := strBuf.String()
3845
return res, nil
3946
}

macros/macros_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ func TestResolveMacros(t *testing.T) {
2626
},
2727
{
2828
givenTemplate: endpointTemplate,
29-
givenParams: UserSyncTemplateParams{GDPR: "SomeGDPR", GDPRConsent: "SomeGDPRConsent"},
29+
givenParams: UserSyncPrivacy{GDPR: "SomeGDPR", GDPRConsent: "SomeGDPRConsent"},
3030
expectedResult: "",
3131
expectedError: true,
3232
},

openrtb_ext/bidders.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ const (
211211
BidderMobileFuse BidderName = "mobilefuse"
212212
BidderMotorik BidderName = "motorik"
213213
BidderNativo BidderName = "nativo"
214+
BidderTheTradeDesk BidderName = "thetradedesk"
214215
BidderNanoInteractive BidderName = "nanointeractive"
215216
BidderNextMillennium BidderName = "nextmillennium"
216217
BidderNinthDecimal BidderName = "ninthdecimal"
@@ -420,6 +421,7 @@ func CoreBidderNames() []BidderName {
420421
BidderMobileFuse,
421422
BidderMotorik,
422423
BidderNativo,
424+
BidderTheTradeDesk,
423425
BidderNanoInteractive,
424426
BidderNextMillennium,
425427
BidderNinthDecimal,

openrtb_ext/imp_thetradedesk.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package openrtb_ext
2+
3+
// ExtImpTheTradeDesk defines the contract for bidrequest.imp[i].ext.prebid.bidder.thetradedesk
4+
type ExtImpTheTradeDesk struct {
5+
PublisherId string `json:"publisherId"`
6+
SupplySourceId string `json:"supplySourceId"`
7+
}

0 commit comments

Comments
 (0)