Skip to content

Commit

Permalink
sspBC Bid Adapter : add support for PAAPI, detection of interstitials…
Browse files Browse the repository at this point in the history
…, and etc. (#12242)

* Update tests for sspBC adapter

Update tests for sspBC adapter:
- change userSync test (due to tcf param appended in v4.6)
- add tests for onBidWon and onTimeout

* [sspbc-adapter] 5.3 updates: content-type for notifications

* [sspbc-adapter] pass CTA to native bid

* [sspbc-5.3] keep pbsize for detected adunits

* [maintenance] - remove old test for sspBc bid adaptor

* [sspbc-5.3] increment adaptor ver

* [sspbc-adapter] maintenance update to sspBCBidAdapter

* remove yarn.lock

* Delete package-lock.json

* remove package-lock.jsonfrom pull request

* [sspbc-adapter] send pageViewId in request

* [sspbc-adapter] update pageViewId test

* [sspbc-adapter] add viewabiility tracker to native ads

* [sspbc-adapter] add support for bid.admNative property

* [sspbc-adapter] ensure that placement id length is always 3 (improves matching response to request)

* [sspbc-adapter] read publisher id and custom ad label, then send them to banner creative

* [sspbc-adapter] adlabel and pubid are set as empty strings, if not present in bid response

* [sspbc-adapter] jstracker data fix

* [sspbc-adapter] jstracker data fix

* [sspbc-adapter] send tagid in notifications

* [sspbc-adapter] add gvlid to spec; prepare getUserSyncs for iframe + image sync

* update remote repo

* cleanup of grupawp/prebid master branch

* update sspBC adapter to v 5.9

* update tests for sspBC bid adapter

* [sspbc-adapter] add support for topicsFPD module

* [sspbc-adapter] change topic segment ids to int

* sspbc-5.94: read bid platform

* sspbc-5.94 wip

* [sspbc-adapter] major version 6.00 (uses backend renderer)

* [sspbc-adapter] 6.0 add support for PAAPI component auctions

* [sspbc-adapter] default platform value for non-bid notifications

* [sspbc-6.0] add default value for native title length

* [sspbc-6.0] include interstitial info in request

* [sspbc-adapter] update to v6, test coverage and smaller fixes

* remove lint console override

---------

Co-authored-by: Wojciech Biały <[email protected]>
Co-authored-by: decemberWP <[email protected]>
  • Loading branch information
3 people authored Sep 17, 2024
1 parent 1f3b684 commit 1f428f4
Show file tree
Hide file tree
Showing 2 changed files with 161 additions and 114 deletions.
164 changes: 62 additions & 102 deletions modules/sspBCBidAdapter.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { deepAccess, getWindowTop, isArray, logWarn } from '../src/utils.js';
import { deepAccess, getWindowTop, isArray, logInfo, logWarn } from '../src/utils.js';
import { ajax } from '../src/ajax.js';
import { config } from '../src/config.js';
import { registerBidder } from '../src/adapters/bidderFactory.js';
Expand All @@ -12,7 +12,7 @@ const SYNC_URL = 'https://ssp.wp.pl/bidder/usersync';
const NOTIFY_URL = 'https://ssp.wp.pl/bidder/notify';
const GVLID = 676;
const TMAX = 450;
const BIDDER_VERSION = '5.93';
const BIDDER_VERSION = '6.00';
const DEFAULT_CURRENCY = 'PLN';
const W = window;
const { navigator } = W;
Expand All @@ -21,7 +21,6 @@ const adUnitsCalled = {};
const adSizesCalled = {};
const bidderRequestsMap = {};
const pageView = {};
var consentApiVersion;

/**
* Native asset mapping - we use constant id per type
Expand Down Expand Up @@ -99,14 +98,16 @@ const getNotificationPayload = bidData => {
tagid: [],
}
bids.forEach(bid => {
const { adUnitCode, cpm, creativeId, meta, mediaType, params: bidParams, bidderRequestId, requestId, timeout } = bid;
const { adUnitCode, cpm, creativeId, meta = {}, mediaType, params: bidParams, bidderRequestId, requestId, timeout } = bid;
const { platform = 'wpartner' } = meta;
const params = unpackParams(bidParams);

// basic notification data
const bidBasicData = {
requestId: bidderRequestId || bidderRequestsMap[requestId],
timeout: timeout || result.timeout,
pvid: pageView.id,
platform
}
result = { ...result, ...bidBasicData }

Expand Down Expand Up @@ -233,10 +234,9 @@ const applyUserIds = (validBidRequest, ortbRequest) => {
const applyGdpr = (bidderRequest, ortbRequest) => {
const { gdprConsent } = bidderRequest;
if (gdprConsent) {
const { apiVersion, gdprApplies, consentString } = gdprConsent;
consentApiVersion = apiVersion;
ortbRequest.regs = Object.assign(ortbRequest.regs, { 'gdpr': gdprApplies ? 1 : 0 });
ortbRequest.user = Object.assign(ortbRequest.user, { 'consent': consentString });
const { gdprApplies, consentString } = gdprConsent;
ortbRequest.regs = Object.assign(ortbRequest.regs || {}, { 'gdpr': gdprApplies ? 1 : 0 });
ortbRequest.user = Object.assign(ortbRequest.user || {}, { 'consent': consentString });
}
}

Expand Down Expand Up @@ -340,7 +340,7 @@ var mapAsset = function mapAsset(paramName, paramValue) {
id: id,
required: required,
title: {
len: len
len: len || 140
}
});
break;
Expand Down Expand Up @@ -469,7 +469,7 @@ var mapVideo = (slot, videoFromBid) => {
const mapImpression = slot => {
const { adUnitCode, bidderRequestId, bidId, params = {}, ortb2Imp = {} } = slot;
const { id, siteId, video } = params;
const { ext = {} } = ortb2Imp;
const { instl, ext = {} } = ortb2Imp;

/*
store bidId <-> bidderRequestId mapping for bidWon notification
Expand Down Expand Up @@ -497,6 +497,7 @@ const mapImpression = slot => {
video: mapVideo(slot, video),
tagid: adUnitCode,
ext,
instl,
};

// Check floorprices for this imp
Expand All @@ -519,6 +520,11 @@ const isNativeAd = bid => {
return bid.admNative || (bid.adm && bid.adm.match(xmlTester));
}

const isHTML = bid => {
const xmlTester = new RegExp(/^<html|<iframe/, 'i');
return bid.adm && bid.adm.match(xmlTester);
}

const parseNative = (nativeData, adUnitCode) => {
const { link = {}, imptrackers: impressionTrackers, jstracker } = nativeData;
const { url: clickUrl, clicktrackers: clickTrackers = [] } = link;
Expand Down Expand Up @@ -572,82 +578,6 @@ const parseNative = (nativeData, adUnitCode) => {
return result;
}

const renderCreative = (site, auctionId, bid, seat, request) => {
const { adLabel, id, slot, sn, page, publisherId, ref } = site;
let gam;

const mcad = {
id: auctionId,
seat,
seatbid: [{
bid: [bid],
}],
};

const mcbase = btoa(encodeURI(JSON.stringify(mcad)));

if (bid.adm) {
// parse adm for gam config
try {
gam = JSON.parse(bid.adm).gam;

if (!gam || !Object.keys(gam).length) {
gam = undefined;
} else {
gam.namedSizes = ['fluid'];
gam.div = 'div-gpt-ad-x01';
gam.targeting = Object.assign(gam.targeting || {}, {
OAS_retarg: '0',
PREBID_ON: '1',
emptygaf: '0',
});
}

if (gam && !gam.targeting) {
gam.targeting = {};
}
} catch (err) {
logWarn('Could not parse adm data', bid.adm);
}
}

let adcode = `<head>
<title></title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
body {
background-color: transparent;
margin: 0;
padding: 0;
}
</style>
<script>
window.rekid = ${id};
window.slot = ${parseInt(slot, 10)};
window.responseTimestamp = ${Date.now()};
window.wp_sn = "${sn}";
window.mcad = JSON.parse(decodeURI(atob("${mcbase}")));
window.tcString = "${request.gdprConsent?.consentString || ''}";
window.page = "${page}";
window.ref = "${ref}";
window.adlabel = "${adLabel || ''}";
window.pubid = "${publisherId || ''}";
window.requestPVID = "${pageView.id}";
`;

adcode += `</script>
</head>
<body>
<div id="c"></div>
<script async crossorigin nomodule src="https://std.wpcdn.pl/wpjslib/wpjslib-inline.js" id="wpjslib"></script>
<script async crossorigin type="module" src="https://std.wpcdn.pl/wpjslib6/wpjslib-inline.js" id="wpjslib6"></script>
</body>
</html>`;

return adcode;
}

const spec = {
code: BIDDER_CODE,
gvlid: GVLID,
Expand Down Expand Up @@ -714,21 +644,22 @@ const spec = {

interpretResponse(serverResponse, request) {
const { bidderRequest } = request;
const response = serverResponse.body;
const { body: response = {} } = serverResponse;
const { seatbid: responseSeat, ext: responseExt = {} } = response;
const { paapi: fledgeAuctionConfigs = [] } = responseExt;
const bids = [];
let site = JSON.parse(request.data).site; // get page and referer data from request
site.sn = response.sn || 'mc_adapter'; // WPM site name (wp_sn)
pageView.sn = site.sn; // store site_name (for syncing and notifications)
let seat;

if (response.seatbid !== undefined) {
if (responseSeat !== undefined) {
/*
Match response to request, by comparing bid id's
'bidid-' prefix indicates oneCode (parameterless) request and response
*/
response.seatbid.forEach(seatbid => {
seat = seatbid.seat;
seatbid.bid.forEach(serverBid => {
responseSeat.forEach(seatbid => {
const { seat, bid } = seatbid;
bid.forEach(serverBid => {
// get data from bid response
const { adomain, crid = `mcad_${bidderRequest.auctionId}_${site.slot}`, impid, exp = 300, ext = {}, price, w, h } = serverBid;

Expand All @@ -744,7 +675,7 @@ const spec = {
const { bidId } = bidRequest || {};

// get ext data from bid
const { siteid = site.id, slotid = site.slot, pubid, adlabel, cache: creativeCache, vurls = [], dsa } = ext;
const { siteid = site.id, slotid = site.slot, pubid, adlabel, cache: creativeCache, vurls = [], dsa, platform = 'wpartner', pricepl } = ext;

// update site data
site = {
Expand Down Expand Up @@ -775,8 +706,9 @@ const spec = {
meta: {
advertiserDomains: adomain,
networkName: seat,
pricepl: ext && ext.pricepl,
pricepl,
dsa,
platform,
},
netRevenue: true,
vurls,
Expand All @@ -790,6 +722,8 @@ const spec = {
bid.vastXml = serverBid.adm;
bid.vastContent = serverBid.adm;
bid.vastUrl = creativeCache;

logInfo(`Bid ${bid.creativeId} is a video ad`);
} else if (isNativeAd(serverBid)) {
// native
bid.mediaType = 'native';
Expand All @@ -803,10 +737,18 @@ const spec = {
logWarn('Could not parse native data', serverBid.adm);
bid.cpm = 0;
}
} else {
// banner ad (default)
logInfo(`Bid ${bid.creativeId} as a native ad`);
} else if (isHTML(serverBid)) {
// banner ad (preformatted)
bid.mediaType = 'banner';
bid.ad = renderCreative(site, response.id, serverBid, seat, bidderRequest);
logInfo(`Bid ${bid.creativeId} as a preformatted banner`);
bid.ad = serverBid.adm;
} else {
// unsupported bid format - send notification and set CPM to zero
const payload = getNotificationPayload(bid);
payload.event = 'parseError';
sendNotification(payload);
bid.cpm = 0;
}

if (bid.cpm > 0) {
Expand All @@ -820,15 +762,14 @@ const spec = {
});
}

return bids;
return fledgeAuctionConfigs.length ? { bids, fledgeAuctionConfigs } : bids;
},
getUserSyncs(syncOptions, serverResponses, gdprConsent) {
getUserSyncs(syncOptions) {
let mySyncs = [];
// TODO: the check on CMP api version does not seem to make sense here. It means "always run the usersync unless an old (v1) CMP was detected". No attention is paid to the consent choices.
if (syncOptions.iframeEnabled && consentApiVersion != 1) {
if (syncOptions.iframeEnabled) {
mySyncs.push({
type: 'iframe',
url: `${SYNC_URL}?tcf=${consentApiVersion}&pvid=${pageView.id}&sn=${pageView.sn}`,
url: `${SYNC_URL}?tcf=2&pvid=${pageView.id}&sn=${pageView.sn}`,
});
};
return mySyncs;
Expand All @@ -843,6 +784,15 @@ const spec = {
}
},

onBidderError(errorData) {
const payload = getNotificationPayload(errorData);
if (payload) {
payload.event = 'parseError';
sendNotification(payload);
return payload;
}
},

onBidViewable(bid) {
const payload = getNotificationPayload(bid);
if (payload) {
Expand All @@ -852,6 +802,15 @@ const spec = {
}
},

onBidBillable(bid) {
const payload = getNotificationPayload(bid);
if (payload) {
payload.event = 'bidBillable';
sendNotification(payload);
return payload;
}
},

onBidWon(bid) {
const payload = getNotificationPayload(bid);
if (payload) {
Expand All @@ -860,6 +819,7 @@ const spec = {
return payload;
}
},

};

registerBidder(spec);
Expand Down
Loading

0 comments on commit 1f428f4

Please sign in to comment.