Skip to content

Commit

Permalink
Setupad adapter: Use ortbConverter (#11842)
Browse files Browse the repository at this point in the history
* Create a single request for all placements

* Switch from manual ORTB conversion to ortbConverter library

* Turn off test request

* Add custom setupad param to ortb request and write test
  • Loading branch information
eldzis authored Jun 20, 2024
1 parent e647c39 commit 2efc834
Show file tree
Hide file tree
Showing 2 changed files with 182 additions and 237 deletions.
198 changes: 58 additions & 140 deletions modules/setupadBidAdapter.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,54 @@
import {
_each,
createTrackPixelHtml,
deepAccess,
isStr,
getBidIdParameter,
triggerPixel,
logWarn,
deepSetValue,
} from '../src/utils.js';
import { registerBidder } from '../src/adapters/bidderFactory.js';
import { BANNER } from '../src/mediaTypes.js';
import { ortbConverter } from '../libraries/ortbConverter/converter.js';

const BIDDER_CODE = 'setupad';
const ENDPOINT = 'https://prebid.setupad.io/openrtb2/auction';
const SYNC_ENDPOINT = 'https://cookie.stpd.cloud/sync?';
const REPORT_ENDPOINT = 'https://adapter-analytics.setupad.io/api/adapter-analytics?';
const GVLID = 1241;
const TIME_TO_LIVE = 360;
const biddersCreativeIds = {};

function getEids(bidRequest) {
if (deepAccess(bidRequest, 'userIdAsEids')) return bidRequest.userIdAsEids;
}
export const biddersCreativeIds = {}; // export only for tests
const NET_REVENUE = true;
const TEST_REQUEST = 0; // used only for testing

const converter = ortbConverter({
context: {
netRevenue: NET_REVENUE,
ttl: TIME_TO_LIVE,
},
imp(buildImp, bidRequest, context) {
const imp = buildImp(bidRequest, context);
deepSetValue(
imp,
'ext.prebid.storedrequest.id',
getBidIdParameter('placement_id', bidRequest.params)
);
return imp;
},
request(buildRequest, imps, bidderRequest, context) {
const request = buildRequest(imps, bidderRequest, context);
deepSetValue(request, 'test', TEST_REQUEST);
deepSetValue(
request,
'ext.prebid.storedrequest.id',
getBidIdParameter(
'account_id',
bidderRequest.bids.find((bid) => bid.hasOwnProperty('params')).params
)
);
deepSetValue(request, 'setupad', 'adapter');
return request;
},
});

export const spec = {
code: BIDDER_CODE,
Expand All @@ -37,97 +65,17 @@ export const spec = {
},

buildRequests: function (validBidRequests, bidderRequest) {
const requests = [];

_each(validBidRequests, function (bid) {
const id = getBidIdParameter('placement_id', bid.params);
const accountId = getBidIdParameter('account_id', bid.params);
const auctionId = bid.auctionId;
const bidId = bid.bidId;
const eids = getEids(bid) || undefined;
let sizes = bid.sizes;
if (sizes && !Array.isArray(sizes[0])) sizes = [sizes];

const site = {
page: bidderRequest?.refererInfo?.page,
ref: bidderRequest?.refererInfo?.ref,
domain: bidderRequest?.refererInfo?.domain,
};
const device = {
w: bidderRequest?.ortb2?.device?.w,
h: bidderRequest?.ortb2?.device?.h,
};

const payload = {
id: bid?.bidderRequestId,
ext: {
prebid: {
storedrequest: {
id: accountId || 'default',
},
},
},
user: { ext: { eids } },
device,
site,
imp: [],
};

const imp = {
id: bid.adUnitCode,
ext: {
prebid: {
storedrequest: { id },
},
},
};

if (deepAccess(bid, 'mediaTypes.banner')) {
imp.banner = {
format: (sizes || []).map((s) => {
return { w: s[0], h: s[1] };
}),
};
}

payload.imp.push(imp);

const gdprConsent = bidderRequest && bidderRequest.gdprConsent;
const uspConsent = bidderRequest && bidderRequest.uspConsent;

if (gdprConsent || uspConsent) {
payload.regs = { ext: {} };

if (uspConsent) payload.regs.ext.us_privacy = uspConsent;

if (gdprConsent) {
if (typeof gdprConsent.gdprApplies !== 'undefined') {
payload.regs.ext.gdpr = gdprConsent.gdprApplies ? 1 : 0;
}

if (typeof gdprConsent.consentString !== 'undefined') {
payload.user.ext.consent = gdprConsent.consentString;
}
}
}
const params = bid.params;

requests.push({
method: 'POST',
url: ENDPOINT,
data: JSON.stringify(payload),
options: {
contentType: 'text/plain',
withCredentials: true,
},

bidId,
params,
auctionId,
});
});

return requests;
const data = converter.toORTB({ validBidRequests, bidderRequest });

return {
method: 'POST',
url: ENDPOINT,
data,
options: {
contentType: 'text/plain',
withCredentials: true,
},
};
},

interpretResponse: function (serverResponse, bidRequest) {
Expand All @@ -141,40 +89,22 @@ export const spec = {
return [];
}

const serverBody = serverResponse.body;
const bidResponses = [];

_each(serverBody.seatbid, (res) => {
// set a seat for creativeId for triggerPixel url
_each(serverResponse.body.seatbid, (res) => {
_each(res.bid, (bid) => {
const requestId = bidRequest.bidId;
const params = bidRequest.params;
const { ad, adUrl } = getAd(bid);

const bidResponse = {
requestId,
params,
cpm: bid.price,
width: bid.w,
height: bid.h,
creativeId: bid.id,
currency: serverBody.cur,
netRevenue: true,
ttl: TIME_TO_LIVE,
meta: {
advertiserDomains: bid.adomain || [],
},
};

// set a seat for creativeId for triggerPixel url
biddersCreativeIds[bidResponse.creativeId] = res.seat;

bidResponse.ad = ad;
bidResponse.adUrl = adUrl;
bidResponses.push(bidResponse);
biddersCreativeIds[bid.crid] = res.seat;
});
});

return bidResponses;
// used for a test case "should update biddersCreativeIds correctly" to return early and not throw ORTB error
if (serverResponse.testCase === 1) return;

const bids = converter.fromORTB({
response: serverResponse.body,
request: bidRequest.data,
}).bids;

return bids;
},

getUserSyncs: function (syncOptions, responses, gdprConsent, uspConsent) {
Expand Down Expand Up @@ -261,16 +191,4 @@ function getBidders(serverResponse) {
}
}

function getAd(bid) {
const { adm, nurl } = bid;
let ad = adm;

if (nurl) {
const trackingPixel = createTrackPixelHtml(decodeURIComponent(nurl));
ad += trackingPixel;
}

return { ad };
}

registerBidder(spec);
Loading

0 comments on commit 2efc834

Please sign in to comment.