Skip to content

Commit 956dea0

Browse files
anthonyrichirAnthony Richir
andauthored
Proxistore Bid Adapter: migration to OpenRTB (#14411)
* Update Proxistore endpoint URLs in adapter and tests Updated the Proxistore `COOKIE_BASE_URL` and `COOKIE_LESS_URL` to the new `abs` domain in both the adapter and its corresponding test file. This ensures consistency with the updated API endpoints. * Integrate OpenRTB converter for Proxistore bid adapter, and add OpenRTB request as a separate field. * Refactor Proxistore bid adapter to improve OpenRTB handling, add GDPR-specific URL selection, and enhance test coverage. * Add support for website and language parameters in Proxistore bid adapter requests, with corresponding test coverage. * Handle empty response body in Proxistore bid adapter to avoid runtime errors. --------- Co-authored-by: Anthony Richir <anthony.richir@proxistore.com>
1 parent 9459b52 commit 956dea0

File tree

3 files changed

+566
-265
lines changed

3 files changed

+566
-265
lines changed

integrationExamples/gpt/proxistore_example.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<html>
22

33
<head>
4-
<script async src="../../build/dev/prebid.js"></script>
4+
<script async src="../../build/dist/prebid.js"></script>
55
<script async src="https://securepubads.g.doubleclick.net/tag/js/gpt.js"></script>
66
<script>
77
var FAILSAFE_TIMEOUT = 3300;

modules/proxistoreBidAdapter.js

Lines changed: 108 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -1,185 +1,160 @@
1-
import { isFn, isPlainObject } from '../src/utils.js';
2-
import { registerBidder } from '../src/adapters/bidderFactory.js';
1+
import {registerBidder} from '../src/adapters/bidderFactory.js';
2+
import {ortbConverter} from '../libraries/ortbConverter/converter.js';
3+
import {BANNER} from '../src/mediaTypes.js';
4+
import {deepSetValue} from '../src/utils.js';
35

46
const BIDDER_CODE = 'proxistore';
57
const PROXISTORE_VENDOR_ID = 418;
6-
const COOKIE_BASE_URL = 'https://abs.proxistore.com/v3/rtb/prebid/multi';
7-
const COOKIE_LESS_URL =
8-
'https://abs.cookieless-proxistore.com/v3/rtb/prebid/multi';
9-
10-
function _createServerRequest(bidRequests, bidderRequest) {
11-
var sizeIds = [];
12-
bidRequests.forEach(function (bid) {
13-
var sizeId = {
14-
id: bid.bidId,
15-
sizes: bid.sizes.map(function (size) {
16-
return {
17-
width: size[0],
18-
height: size[1],
19-
};
20-
}),
21-
floor: _assignFloor(bid),
22-
segments: _assignSegments(bid),
23-
};
24-
sizeIds.push(sizeId);
25-
});
26-
var payload = {
27-
// TODO: fix auctionId leak: https://github.com/prebid/Prebid.js/issues/9781
28-
auctionId: bidRequests[0].auctionId,
29-
transactionId: bidRequests[0].ortb2Imp?.ext?.tid,
30-
bids: sizeIds,
31-
website: bidRequests[0].params.website,
32-
language: bidRequests[0].params.language,
33-
gdpr: {
34-
applies: false,
35-
consentGiven: false,
36-
},
37-
};
8+
const COOKIE_BASE_URL = 'https://abs.proxistore.com/v3/rtb/openrtb';
9+
const COOKIE_LESS_URL = 'https://abs.cookieless-proxistore.com/v3/rtb/openrtb';
10+
const SYNC_BASE_URL = 'https://abs.proxistore.com/v3/rtb/sync';
11+
12+
const converter = ortbConverter({
13+
context: {
14+
mediaType: BANNER,
15+
netRevenue: true,
16+
ttl: 30,
17+
currency: 'EUR',
18+
},
19+
request(buildRequest, imps, bidderRequest, context) {
20+
const request = buildRequest(imps, bidderRequest, context);
21+
const bidRequests = context.bidRequests;
22+
if (bidRequests && bidRequests.length > 0) {
23+
const params = bidRequests[0].params;
24+
if (params.website) {
25+
deepSetValue(request, 'ext.proxistore.website', params.website);
26+
}
27+
if (params.language) {
28+
deepSetValue(request, 'ext.proxistore.language', params.language);
29+
}
30+
}
31+
return request;
32+
}
33+
});
3834

39-
if (bidderRequest && bidderRequest.gdprConsent) {
40-
var gdprConsent = bidderRequest.gdprConsent;
35+
/**
36+
* Determines whether or not the given bid request is valid.
37+
*
38+
* @param bid The bid params to validate.
39+
* @return boolean True if this is a valid bid, and false otherwise.
40+
*/
41+
function isBidRequestValid(bid) {
42+
return !!(bid.params.website && bid.params.language);
43+
}
4144

42-
if (
43-
typeof gdprConsent.gdprApplies === 'boolean' &&
44-
gdprConsent.gdprApplies
45-
) {
46-
payload.gdpr.applies = true;
47-
}
45+
/**
46+
* Make a server request from the list of BidRequests.
47+
*
48+
* @param bidRequests - an array of bids
49+
* @param bidderRequest
50+
* @return ServerRequest Info describing the request to the server.
51+
*/
52+
function buildRequests(bidRequests, bidderRequest) {
53+
let gdprApplies = false;
54+
let consentGiven = false;
55+
56+
if (bidderRequest && bidderRequest.gdprConsent) {
57+
const gdprConsent = bidderRequest.gdprConsent;
4858

49-
if (
50-
typeof gdprConsent.consentString === 'string' &&
51-
gdprConsent.consentString
52-
) {
53-
payload.gdpr.consentString = bidderRequest.gdprConsent.consentString;
59+
if (typeof gdprConsent.gdprApplies === 'boolean' && gdprConsent.gdprApplies) {
60+
gdprApplies = true;
5461
}
5562

5663
if (gdprConsent.vendorData) {
57-
var vendorData = gdprConsent.vendorData;
58-
64+
const vendorData = gdprConsent.vendorData;
5965
if (
6066
vendorData.vendor &&
6167
vendorData.vendor.consents &&
62-
typeof vendorData.vendor.consents[PROXISTORE_VENDOR_ID.toString(10)] !==
63-
'undefined'
68+
vendorData.vendor.consents[PROXISTORE_VENDOR_ID.toString(10)] !== 'undefined'
6469
) {
65-
payload.gdpr.consentGiven =
66-
!!vendorData.vendor.consents[PROXISTORE_VENDOR_ID.toString(10)];
70+
consentGiven = !!vendorData.vendor.consents[PROXISTORE_VENDOR_ID.toString(10)];
6771
}
6872
}
6973
}
7074

71-
var options = {
75+
const options = {
7276
contentType: 'application/json',
73-
withCredentials: payload.gdpr.consentGiven,
77+
withCredentials: consentGiven,
7478
customHeaders: {
75-
version: '1.0.4',
79+
version: '2.0.0',
7680
},
7781
};
78-
var endPointUri =
79-
payload.gdpr.consentGiven || !payload.gdpr.applies
80-
? COOKIE_BASE_URL
81-
: COOKIE_LESS_URL;
82+
83+
const endPointUri = consentGiven || !gdprApplies ? COOKIE_BASE_URL : COOKIE_LESS_URL;
8284

8385
return {
8486
method: 'POST',
8587
url: endPointUri,
86-
data: JSON.stringify(payload),
88+
data: converter.toORTB({ bidRequests, bidderRequest }),
8789
options: options,
8890
};
8991
}
9092

91-
function _assignSegments(bid) {
92-
var segs = (bid.ortb2 && bid.ortb2.user && bid.ortb2.user.ext && bid.ortb2.user.ext.data && bid.ortb2.user.ext.data.sd_rtd && bid.ortb2.user.ext.data.sd_rtd.segments ? bid.ortb2.user.ext.data.sd_rtd.segments : []);
93-
var cats = {};
94-
if (bid.ortb2 && bid.ortb2.site && bid.ortb2.site.ext && bid.ortb2.site.ext.data && bid.ortb2.site.ext.data.sd_rtd) {
95-
if (bid.ortb2.site.ext.data.sd_rtd.categories) {
96-
segs = segs.concat(bid.ortb2.site.ext.data.sd_rtd.categories);
97-
}
98-
if (bid.ortb2.site.ext.data.sd_rtd.categories_score) {
99-
cats = bid.ortb2.site.ext.data.sd_rtd.categories_score;
100-
}
101-
}
102-
103-
return {
104-
segments: segs,
105-
contextual_categories: cats
106-
};
107-
}
108-
109-
function _createBidResponse(response) {
110-
return {
111-
requestId: response.requestId,
112-
cpm: response.cpm,
113-
width: response.width,
114-
height: response.height,
115-
ad: response.ad,
116-
ttl: response.ttl,
117-
creativeId: response.creativeId,
118-
currency: response.currency,
119-
netRevenue: response.netRevenue,
120-
vastUrl: response.vastUrl,
121-
vastXml: response.vastXml,
122-
dealId: response.dealId,
123-
meta: response.meta,
124-
};
125-
}
12693
/**
127-
* Determines whether or not the given bid request is valid.
94+
* Unpack the response from the server into a list of bids.
12895
*
129-
* @param bid The bid params to validate.
130-
* @return boolean True if this is a valid bid, and false otherwise.
96+
* @param response
97+
* @param request
98+
* @return An array of bids which were nested inside the server.
13199
*/
132-
133-
function isBidRequestValid(bid) {
134-
return !!(bid.params.website && bid.params.language);
100+
function interpretResponse(response, request) {
101+
if (response.body) {
102+
return converter.fromORTB({response: response.body, request: request.data}).bids;
103+
}
104+
return [];
135105
}
136-
/**
137-
* Make a server request from the list of BidRequests.
138-
*
139-
* @param bidRequests - an array of bids
140-
* @param bidderRequest
141-
* @return ServerRequest Info describing the request to the server.
142-
*/
143-
144-
function buildRequests(bidRequests, bidderRequest) {
145-
var request = _createServerRequest(bidRequests, bidderRequest);
146106

147-
return request;
148-
}
149107
/**
150-
* Unpack the response from the server into a list of bids.
108+
* Register user sync pixels and iframes.
151109
*
152-
* @param serverResponse A successful response from the server.
153-
* @param bidRequest Request original server request
154-
* @return An array of bids which were nested inside the server.
110+
* @param syncOptions - which sync types are enabled
111+
* @param responses - server responses
112+
* @param gdprConsent - GDPR consent data
113+
* @return Array of sync objects
155114
*/
115+
function getUserSyncs(syncOptions, responses, gdprConsent) {
116+
const syncs = [];
156117

157-
function interpretResponse(serverResponse, bidRequest) {
158-
return serverResponse.body.map(_createBidResponse);
159-
}
118+
// Only sync if consent given or GDPR doesn't apply
119+
const consentGiven = gdprConsent?.vendorData?.vendor?.consents?.[PROXISTORE_VENDOR_ID];
120+
if (gdprConsent?.gdprApplies && !consentGiven) {
121+
return syncs;
122+
}
160123

161-
function _assignFloor(bid) {
162-
if (!isFn(bid.getFloor)) {
163-
return bid.params.bidFloor ? bid.params.bidFloor : null;
124+
const params = new URLSearchParams();
125+
if (gdprConsent) {
126+
params.set('gdpr', gdprConsent.gdprApplies ? '1' : '0');
127+
if (gdprConsent.consentString) {
128+
params.set('gdpr_consent', gdprConsent.consentString);
129+
}
130+
}
131+
132+
if (syncOptions.pixelEnabled) {
133+
syncs.push({
134+
type: 'image',
135+
url: `${SYNC_BASE_URL}/image?${params}`
136+
});
164137
}
165-
const floor = bid.getFloor({
166-
currency: 'EUR',
167-
mediaType: 'banner',
168-
size: '*',
169-
});
170138

171-
if (isPlainObject(floor) && !isNaN(floor.floor) && floor.currency === 'EUR') {
172-
return floor.floor;
139+
if (syncOptions.iframeEnabled) {
140+
syncs.push({
141+
type: 'iframe',
142+
url: `${SYNC_BASE_URL}/iframe?${params}`
143+
});
173144
}
174-
return null;
145+
146+
return syncs;
175147
}
176148

177149
export const spec = {
178150
code: BIDDER_CODE,
151+
gvlid: PROXISTORE_VENDOR_ID,
179152
isBidRequestValid: isBidRequestValid,
180153
buildRequests: buildRequests,
181154
interpretResponse: interpretResponse,
182-
gvlid: PROXISTORE_VENDOR_ID,
155+
getUserSyncs: getUserSyncs,
156+
supportedMediaTypes: [BANNER],
157+
browsingTopics: true,
183158
};
184159

185160
registerBidder(spec);

0 commit comments

Comments
 (0)