Skip to content

Commit

Permalink
Sspbc Bid Adapter: Gather language in payload; various formatting cha…
Browse files Browse the repository at this point in the history
…nges (#8395)

* 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

* [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

* [sspbc-adapter] fix notification payload

* [sspbc-adapter] fix notification payload, fix tests

* [sspbc-adapter] add userIds to ortb request

* [sspbc-adapter] update to 4.1, change request to be ortb 2.6 compliant

* [sspbc-adapter] update tests

* [ssbc-adapter] bid cache for video ads

* [sspbc-adapter] add PageView.id to banner ad; update tests

* [sspbc-adapter] fix window.gam not being added to banner html

* [sspbc-adapter] send device / content language

* [sspbc-adapter] send pageview and site ids to user sync frame

* [sspbc-adapter] add ES6 version of common ad library (for banner creatives)

* [sspbc-adapter] move content property

* [sspbc-adapter] reorganize notification payload creator

* [sspbc-adapter] store PLN price in meta; send in bidWon notification

* [sspbc-adapter] add playbackmethod to supporten video params; allow overridinbg video settngs via  bid.params.video

* [sspbc-adapter] update md

* [sspbc-adapter] fix error in mapVideo method (Object assign merror when mediaTypes do not contain video)

Co-authored-by: Wojciech Biały <wb@WojciechBialy.local>
  • Loading branch information
wojciech-bialy-wpm and Wojciech Biały committed May 12, 2022
1 parent 7a80c65 commit 37cf17f
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 37 deletions.
131 changes: 95 additions & 36 deletions modules/sspBCBidAdapter.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import {deepAccess, isArray, logWarn, parseUrl} from '../src/utils.js';
import {ajax} from '../src/ajax.js';
import {registerBidder} from '../src/adapters/bidderFactory.js';
import {BANNER, NATIVE, VIDEO} from '../src/mediaTypes.js';
import {includes as strIncludes} from '../src/polyfill.js';
import { deepAccess, isArray, logWarn, parseUrl, getWindowTop } from '../src/utils.js';
import { ajax } from '../src/ajax.js';
import { config } from '../src/config.js';
import { registerBidder } from '../src/adapters/bidderFactory.js';
import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js';
import { includes as strIncludes } from '../src/polyfill.js';

const BIDDER_CODE = 'sspBC';
const BIDDER_URL = 'https://ssp.wp.pl/bidder/';
Expand All @@ -11,7 +12,8 @@ const NOTIFY_URL = 'https://ssp.wp.pl/bidder/notify';
const TRACKER_URL = 'https://bdr.wpcdn.pl/tag/jstracker.js';
const GVLID = 676;
const TMAX = 450;
const BIDDER_VERSION = '5.41';
const BIDDER_VERSION = '5.6';
const DEFAULT_CURRENCY = 'PLN';
const W = window;
const { navigator } = W;
const oneCodeDetection = {};
Expand All @@ -20,6 +22,25 @@ const adSizesCalled = {};
const pageView = {};
var consentApiVersion;

/**
* Get preferred language of browser (i.e. user)
* @returns {string} languageCode - ISO language code
*/
const getBrowserLanguage = () => navigator.language || (navigator.languages && navigator.languages[0]);

/**
* Get language of top level html object
* @returns {string} languageCode - ISO language code
*/
const getContentLanguage = () => {
try {
const topWindow = getWindowTop();
return topWindow.document.body.parentNode.lang;
} catch (err) {
logWarn('Could not read language form top-level html', err);
}
};

/**
* Get bid parameters for notification
* @param {*} bidData - bid (bidWon), or array of bids (timeout)
Expand All @@ -28,38 +49,50 @@ const getNotificationPayload = bidData => {
if (bidData) {
const bids = isArray(bidData) ? bidData : [bidData];
if (bids.length > 0) {
const result = {
let result = {
requestId: undefined,
siteId: [],
slotId: [],
tagid: [],
}
bids.forEach(bid => {
let params = isArray(bid.params) ? bid.params[0] : bid.params;
const { adUnitCode, auctionId, cpm, creativeId, meta, params: bidParams, requestId, timeout } = bid;
let params = isArray(bidParams) ? bidParams[0] : bidParams;
params = params || {};

// check for stored detection
if (oneCodeDetection[bid.requestId]) {
params.siteId = oneCodeDetection[bid.requestId][0];
params.id = oneCodeDetection[bid.requestId][1];
// basic notification data
const bidBasicData = {
requestId: auctionId || result.requestId,
timeout: timeout || result.timeout,
pvid: pageView.id,
}
result = { ...result, ...bidBasicData }

result.tagid.push(adUnitCode);

// check for stored detection
if (oneCodeDetection[requestId]) {
params.siteId = oneCodeDetection[requestId][0];
params.id = oneCodeDetection[requestId][1];
}
if (params.siteId) {
result.siteId.push(params.siteId);
}
if (params.id) {
result.slotId.push(params.id);
}
if (bid.cpm) {
const meta = bid.meta || {};
result.cpm = bid.cpm;
result.creativeId = bid.creativeId;
result.adomain = meta.advertiserDomains && meta.advertiserDomains[0];
result.networkName = meta.networkName;

if (cpm) {
// non-empty bid data
const bidNonEmptyData = {
cpm,
cpmpl: meta && meta.pricepl,
creativeId,
adomain: meta && meta.advertiserDomains && meta.advertiserDomains[0],
networkName: meta && meta.networkName,
}
result = { ...result, ...bidNonEmptyData }
}
result.tagid.push(bid.adUnitCode);
result.requestId = bid.auctionId || result.requestId;
result.timeout = bid.timeout || result.timeout;
})
return result;
}
Expand Down Expand Up @@ -97,7 +130,7 @@ const applyClientHints = ortbRequest => {
*/
if (!pageView.id || location.pathname !== pageView.path) {
pageView.path = location.pathname;
pageView.id = Math.floor(1E20 * Math.random());
pageView.id = Math.floor(1E20 * Math.random()).toString();
}

Object.keys(hints).forEach(key => {
Expand All @@ -120,7 +153,7 @@ const applyClientHints = ortbRequest => {
name: 'pvid',
segment: [
{
value: `${pageView.id}`
value: pageView.id
}
]
}];
Expand Down Expand Up @@ -151,6 +184,12 @@ const applyGdpr = (bidderRequest, ortbRequest) => {
}
}

/**
* Get currency (either default or adserver)
* @returns {string} currency name
*/
const getCurrency = () => config.getConfig('currency.adServerCurrency') || DEFAULT_CURRENCY;

/**
* Get value for first occurence of key within the collection
*/
Expand Down Expand Up @@ -260,12 +299,13 @@ const mapNative = slot => {
return assets ? { request: JSON.stringify({ native: { assets } }) } : undefined;
}

var mapVideo = slot => {
var video = deepAccess(slot, 'mediaTypes.video');
var videoParamsUsed = ['api', 'context', 'linearity', 'maxduration', 'mimes', 'protocols'];
var mapVideo = (slot, videoFromBid) => {
var videoFromSlot = deepAccess(slot, 'mediaTypes.video');
var videoParamsUsed = ['api', 'context', 'linearity', 'maxduration', 'mimes', 'protocols', 'playbackmethod'];
var videoAssets;

if (video) {
if (videoFromSlot) {
const video = videoFromBid ? Object.assign(videoFromSlot, videoFromBid) : videoFromSlot;
var videoParams = Object.keys(video);
var playerSize = video.playerSize;
videoAssets = {}; // player width / height
Expand All @@ -292,7 +332,7 @@ var mapVideo = slot => {

const mapImpression = slot => {
const { adUnitCode, bidId, params = {}, ortb2Imp = {} } = slot;
const { id, siteId } = params;
const { id, siteId, video } = params;
const { ext = {} } = ortb2Imp;

/*
Expand All @@ -313,12 +353,13 @@ const mapImpression = slot => {
id: id && siteId ? id.padStart(3, '0') : 'bidid-' + bidId,
banner: mapBanner(slot),
native: mapNative(slot),
video: mapVideo(slot),
video: mapVideo(slot, video),
tagid: adUnitCode,
ext,
};

// Check floorprices for this imp
const currency = getCurrency();
if (typeof slot.getFloor === 'function') {
var bannerFloor = 0;
var nativeFloor = 0;
Expand All @@ -328,20 +369,24 @@ const mapImpression = slot => {
bannerFloor = slot.sizes.reduce(function (prev, next) {
var currentFloor = slot.getFloor({
mediaType: 'banner',
size: next
size: next,
currency
}).floor;
return prev > currentFloor ? prev : currentFloor;
}, 0);
}

nativeFloor = slot.getFloor({
mediaType: 'native'
mediaType: 'native', currency
});
videoFloor = slot.getFloor({
mediaType: 'video'
mediaType: 'video', currency
});
imp.bidfloor = Math.max(bannerFloor, nativeFloor, videoFloor);
} else {
imp.bidfloor = 0;
}
imp.bidfloorcur = currency;
return imp;
}

Expand Down Expand Up @@ -463,13 +508,19 @@ const renderCreative = (site, auctionId, bid, seat, request) => {
window.ref = "${site.ref}";
window.adlabel = "${site.adLabel ? site.adLabel : ''}";
window.pubid = "${site.publisherId ? site.publisherId : ''}";
window.requestPVID = "${pageView.id}";
`;

if (gam) {
adcode += `window.gam = ${JSON.stringify(gam)};`;
}

adcode += `</script>
</head>
<body>
<div id="c"></div>
<script id="wpjslib" crossorigin src="//std.wpcdn.pl/wpjslib/wpjslib-inline.js" async defer></script>
<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>`;

Expand Down Expand Up @@ -512,12 +563,15 @@ const spec = {
publisher: publisherId ? { id: publisherId } : undefined,
page,
domain,
ref
ref,
content: { language: getContentLanguage() },
},
imp: validBidRequests.map(slot => mapImpression(slot)),
cur: [getCurrency()],
tmax,
user: {},
regs: {},
device: { language: getBrowserLanguage() },
test: testMode,
};

Expand All @@ -539,6 +593,7 @@ const spec = {
const bids = [];
const 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) {
Expand All @@ -547,6 +602,7 @@ const spec = {
'bidid-' prefix indicates oneCode (parameterless) request and response
*/
response.seatbid.forEach(seatbid => {
let creativeCache;
seat = seatbid.seat;
seatbid.bid.forEach(serverBid => {
// get data from bid response
Expand All @@ -572,11 +628,12 @@ const spec = {
ext also might contain publisherId and custom ad label
*/
const { siteid, slotid, pubid, adlabel } = ext;
const { siteid, slotid, pubid, adlabel, cache } = ext;
site.id = siteid || site.id;
site.slot = slotid || site.slot;
site.publisherId = pubid;
site.adLabel = adlabel;
creativeCache = cache;
}

if (bidRequest && site.id && !strIncludes(site.id, 'bidid')) {
Expand All @@ -597,6 +654,7 @@ const spec = {
meta: {
advertiserDomains: adomain,
networkName: seat,
pricepl: ext && ext.pricepl,
},
netRevenue: true,
};
Expand All @@ -608,6 +666,7 @@ const spec = {
bid.mediaType = 'video';
bid.vastXml = serverBid.adm;
bid.vastContent = serverBid.adm;
bid.vastUrl = creativeCache;
} else if (isNativeAd(serverBid)) {
// native
bid.mediaType = 'native';
Expand Down Expand Up @@ -662,7 +721,7 @@ const spec = {
if (syncOptions.iframeEnabled && consentApiVersion != 1) {
mySyncs.push({
type: 'iframe',
url: `${SYNC_URL}?tcf=${consentApiVersion}`,
url: `${SYNC_URL}?tcf=${consentApiVersion}&pvid=${pageView.id}&sn=${pageView.sn}`,
});
};
return mySyncs;
Expand Down
1 change: 1 addition & 0 deletions modules/sspBCBidAdapter.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Optional parameters:
- page
- tmax
- test
- video

# Test Parameters
```
Expand Down
5 changes: 4 additions & 1 deletion test/spec/modules/sspBCBidAdapter_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,7 @@ describe('SSPBC adapter', function () {
'ext': {
'siteid': '8816',
'slotid': '150',
'cache': 'https://video.tag.cache'
},
}],
'seat': 'dsp1',
Expand Down Expand Up @@ -631,6 +632,7 @@ describe('SSPBC adapter', function () {
expect(adcode).to.contain('window.mcad');
expect(adcode).to.contain('window.gdpr');
expect(adcode).to.contain('window.page');
expect(adcode).to.contain('window.requestPVID');
});

it('should create a correct video bid', function () {
Expand All @@ -639,11 +641,12 @@ describe('SSPBC adapter', function () {
expect(resultVideo.length).to.equal(1);

let videoBid = resultVideo[0];
expect(videoBid).to.have.keys('adType', 'bidderCode', 'cpm', 'creativeId', 'currency', 'width', 'height', 'meta', 'mediaType', 'netRevenue', 'requestId', 'ttl', 'vastContent', 'vastXml');
expect(videoBid).to.have.keys('adType', 'bidderCode', 'cpm', 'creativeId', 'currency', 'width', 'height', 'meta', 'mediaType', 'netRevenue', 'requestId', 'ttl', 'vastContent', 'vastXml', 'vastUrl');
expect(videoBid.adType).to.equal('instream');
expect(videoBid.mediaType).to.equal('video');
expect(videoBid.vastXml).to.match(/^<\?xml.*<\/VAST>$/);
expect(videoBid.vastContent).to.match(/^<\?xml.*<\/VAST>$/);
expect(videoBid.vastUrl).to.equal('https://video.tag.cache');
});

it('should create a correct native bid', function () {
Expand Down

0 comments on commit 37cf17f

Please sign in to comment.