Skip to content

Commit

Permalink
Adnuntius Bid Adaptor: Handle voidAuIds from server response (#10646)
Browse files Browse the repository at this point in the history
- invalid ad units are put into a voidAuIds array from
the ad server.
- this stores those ad units into local storage and prevents
calling to those ad units.
- also handles any values from metaData from the adserver response.
  • Loading branch information
antosarho authored Nov 30, 2023
1 parent d70097e commit 7974ebc
Show file tree
Hide file tree
Showing 2 changed files with 282 additions and 59 deletions.
222 changes: 171 additions & 51 deletions modules/adnuntiusBidAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,39 +15,146 @@ const GVLID = 855;
const DEFAULT_VAST_VERSION = 'vast4'
const MAXIMUM_DEALS_LIMIT = 5;
const VALID_BID_TYPES = ['netBid', 'grossBid'];
const META_DATA_KEY = 'adn.metaData';

const checkSegment = function (segment) {
if (isStr(segment)) return segment;
if (segment.id) return segment.id
}
export const misc = {
getUnixTimestamp: function(addDays, asMinutes) {
const multiplication = addDays / (asMinutes ? 1440 : 1);
return Date.now() + (addDays && addDays > 0 ? (1000 * 60 * 60 * 24 * multiplication) : 0);
}
};

const storageTool = (function() {
const storage = getStorageManager({bidderCode: BIDDER_CODE});
let metaInternal;

const getMetaInternal = function() {
if (!storage.localStorageIsEnabled()) {
return {};
}

let parsedJson;
try {
parsedJson = JSON.parse(storage.getDataFromLocalStorage(META_DATA_KEY));
} catch (e) {
return {};
}

let filteredEntries = parsedJson ? parsedJson.filter((datum) => {
if (datum.key === 'voidAuIds' && Array.isArray(datum.value)) {
return true;
}
return datum.key && datum.value && datum.exp && datum.exp > misc.getUnixTimestamp();
}) : [];
const voidAuIdsEntry = filteredEntries.find(entry => entry.key === 'voidAuIds');
if (voidAuIdsEntry) {
const now = misc.getUnixTimestamp();
voidAuIdsEntry.value = voidAuIdsEntry.value.filter(voidAuId => voidAuId.auId && voidAuId.exp > now);
if (!voidAuIdsEntry.value.length) {
filteredEntries = filteredEntries.filter(entry => entry.key !== 'voidAuIds');
}
}
return filteredEntries;
};

const setMetaInternal = function(apiResponse) {
if (!storage.localStorageIsEnabled()) {
return;
}

const updateVoidAuIds = function(currentVoidAuIds, auIdsAsString) {
const newAuIds = auIdsAsString ? auIdsAsString.split(';') : [];
const notNewExistingAuIds = currentVoidAuIds.filter(auIdObj => {
return newAuIds.indexOf(auIdObj.value) < -1;
}) || [];
const oneDayFromNow = misc.getUnixTimestamp(1);
const apiIdsArray = newAuIds.map(auId => {
return {exp: oneDayFromNow, auId: auId};
}) || [];
return notNewExistingAuIds.concat(apiIdsArray) || [];
}

const getSegmentsFromOrtb = function (ortb2) {
const userData = deepAccess(ortb2, 'user.data');
let segments = [];
if (userData) {
userData.forEach(userdat => {
if (userdat.segment) {
segments.push(...userdat.segment.filter(checkSegment).map(checkSegment));
const metaAsObj = getMetaInternal().reduce((a, entry) => ({...a, [entry.key]: {value: entry.value, exp: entry.exp}}), {});
for (const key in apiResponse) {
if (key !== 'voidAuIds') {
metaAsObj[key] = {
value: apiResponse[key],
exp: misc.getUnixTimestamp(100)
}
}
}
const currentAuIds = updateVoidAuIds(metaAsObj.voidAuIds || [], apiResponse.voidAuIds || []);
if (currentAuIds.length > 0) {
metaAsObj.voidAuIds = {value: currentAuIds};
}
const metaDataForSaving = Object.entries(metaAsObj).map((entrySet) => {
if (entrySet[0] === 'voidAuIds') {
return {
key: entrySet[0],
value: entrySet[1].value
};
}
return {
key: entrySet[0],
value: entrySet[1].value,
exp: entrySet[1].exp
}
});
storage.setDataInLocalStorage(META_DATA_KEY, JSON.stringify(metaDataForSaving));
};

const getUsi = function(meta, ortb2) {
let usi = (meta && meta.usi) ? meta.usi : false;
if (ortb2 && ortb2.user && ortb2.user.id) {
usi = ortb2.user.id
}
return usi;
}
return segments
}

const handleMeta = function () {
const storage = getStorageManager({ bidderCode: BIDDER_CODE })
let adnMeta = null
if (storage.localStorageIsEnabled()) {
adnMeta = JSON.parse(storage.getDataFromLocalStorage('adn.metaData'))
const getSegmentsFromOrtb = function (ortb2) {
const userData = deepAccess(ortb2, 'user.data');
let segments = [];
if (userData) {
userData.forEach(userdat => {
if (userdat.segment) {
segments.push(...userdat.segment.map((segment) => {
if (isStr(segment)) return segment;
if (isStr(segment.id)) return segment.id;
}).filter((seg) => !!seg));
}
});
}
return segments
}
return (adnMeta !== null) ? adnMeta.reduce((acc, cur) => { return { ...acc, [cur.key]: cur.value } }, {}) : {}
}

const getUsi = function (meta, ortb2, bidderRequest) {
let usi = (meta !== null && meta.usi) ? meta.usi : false;
if (ortb2 && ortb2.user && ortb2.user.id) { usi = ortb2.user.id }
return usi
}
return {
refreshStorage: function(bidderRequest) {
const ortb2 = bidderRequest.ortb2 || {};
metaInternal = getMetaInternal().reduce((a, entry) => ({...a, [entry.key]: entry.value}), {});
metaInternal.usi = getUsi(metaInternal, ortb2);
if (!metaInternal.usi) {
delete metaInternal.usi;
}
if (metaInternal.voidAuIds) {
metaInternal.voidAuIdsArray = metaInternal.voidAuIds.map((voidAuId) => {
return voidAuId.auId;
});
}
metaInternal.segments = getSegmentsFromOrtb(ortb2);
},
saveToStorage: function(serverData) {
setMetaInternal(serverData);
},
getUrlRelatedData: function() {
const {segments, usi, voidAuIdsArray} = metaInternal;
return {segments, usi, voidAuIdsArray};
},
getPayloadRelatedData: function() {
const {segments, usi, userId, voidAuIdsArray, voidAuIds, ...payloadRelatedData} = metaInternal;
return payloadRelatedData;
}
};
})();

const validateBidType = function(bidTypeOption) {
return VALID_BID_TYPES.indexOf(bidTypeOption || '') > -1 ? bidTypeOption : 'bid';
Expand All @@ -67,34 +174,34 @@ export const spec = {
},

buildRequests: function (validBidRequests, bidderRequest) {
const networks = {};
const bidRequests = {};
const requests = [];
const request = [];
const ortb2 = bidderRequest.ortb2 || {};
const bidderConfig = config.getConfig();
const queryParamsAndValues = [];
queryParamsAndValues.push('tzo=' + new Date().getTimezoneOffset())
queryParamsAndValues.push('format=json')

const adnMeta = handleMeta()
const usi = getUsi(adnMeta, ortb2, bidderRequest)
const segments = getSegmentsFromOrtb(ortb2);
const tzo = new Date().getTimezoneOffset();
const gdprApplies = deepAccess(bidderRequest, 'gdprConsent.gdprApplies');
const consentString = deepAccess(bidderRequest, 'gdprConsent.consentString');
if (gdprApplies !== undefined) queryParamsAndValues.push('consentString=' + consentString);

request.push('tzo=' + tzo)
request.push('format=json')
storageTool.refreshStorage(bidderRequest);

if (gdprApplies !== undefined) request.push('consentString=' + consentString);
if (segments.length > 0) request.push('segments=' + segments.join(','));
if (usi) request.push('userId=' + usi);
if (bidderConfig.useCookie === false) request.push('noCookies=true');
if (bidderConfig.maxDeals > 0) request.push('ds=' + Math.min(bidderConfig.maxDeals, MAXIMUM_DEALS_LIMIT));
const urlRelatedMetaData = storageTool.getUrlRelatedData();
if (urlRelatedMetaData.segments.length > 0) queryParamsAndValues.push('segments=' + urlRelatedMetaData.segments.join(','));
if (urlRelatedMetaData.usi) queryParamsAndValues.push('userId=' + urlRelatedMetaData.usi);

const bidderConfig = config.getConfig();
if (bidderConfig.useCookie === false) queryParamsAndValues.push('noCookies=true');
if (bidderConfig.maxDeals > 0) queryParamsAndValues.push('ds=' + Math.min(bidderConfig.maxDeals, MAXIMUM_DEALS_LIMIT));

const bidRequests = {};
const networks = {};
for (let i = 0; i < validBidRequests.length; i++) {
const bid = validBidRequests[i]
let network = bid.params.network || 'network';
const maxDeals = Math.max(0, Math.min(bid.params.maxDeals || 0, MAXIMUM_DEALS_LIMIT));
const targeting = bid.params.targeting || {};
const bid = validBidRequests[i];
if ((urlRelatedMetaData.voidAuIdsArray && (urlRelatedMetaData.voidAuIdsArray.indexOf(bid.params.auId) > -1 || urlRelatedMetaData.voidAuIdsArray.indexOf(bid.params.auId.padStart(16, '0')) > -1))) {
// This auId is void. Do NOT waste time and energy sending a request to the server
continue;
}

let network = bid.params.network || 'network';
if (bid.mediaTypes && bid.mediaTypes.video && bid.mediaTypes.video.context !== 'outstream') {
network += '_video'
}
Expand All @@ -105,21 +212,31 @@ export const spec = {
networks[network] = networks[network] || {};
networks[network].adUnits = networks[network].adUnits || [];
if (bidderRequest && bidderRequest.refererInfo) networks[network].context = bidderRequest.refererInfo.page;
if (adnMeta) networks[network].metaData = adnMeta;
const adUnit = { ...targeting, auId: bid.params.auId, targetId: bid.bidId, maxDeals: maxDeals }

const payloadRelatedData = storageTool.getPayloadRelatedData();
if (Object.keys(payloadRelatedData).length > 0) {
networks[network].metaData = payloadRelatedData;
}

const targeting = bid.params.targeting || {};
const adUnit = { ...targeting, auId: bid.params.auId, targetId: bid.params.targetId || bid.bidId };
const maxDeals = Math.max(0, Math.min(bid.params.maxDeals || 0, MAXIMUM_DEALS_LIMIT));
if (maxDeals > 0) {
adUnit.maxDeals = maxDeals;
}
if (bid.mediaTypes && bid.mediaTypes.banner && bid.mediaTypes.banner.sizes) adUnit.dimensions = bid.mediaTypes.banner.sizes
networks[network].adUnits.push(adUnit);
}

const requests = [];
const networkKeys = Object.keys(networks)
for (let j = 0; j < networkKeys.length; j++) {
const network = networkKeys[j];
const networkRequest = [...request]
if (network.indexOf('_video') > -1) { networkRequest.push('tt=' + DEFAULT_VAST_VERSION) }
if (network.indexOf('_video') > -1) { queryParamsAndValues.push('tt=' + DEFAULT_VAST_VERSION) }
const requestURL = gdprApplies ? ENDPOINT_URL_EUROPE : ENDPOINT_URL
requests.push({
method: 'POST',
url: requestURL + '?' + networkRequest.join('&'),
url: requestURL + '?' + queryParamsAndValues.join('&'),
data: JSON.stringify(networks[network]),
bid: bidRequests[network]
});
Expand All @@ -129,6 +246,9 @@ export const spec = {
},

interpretResponse: function (serverResponse, bidRequest) {
if (serverResponse.body.metaData) {
storageTool.saveToStorage(serverResponse.body.metaData);
}
const adUnits = serverResponse.body.adUnits;

let validatedBidType = validateBidType(config.getConfig().bidType);
Expand Down
Loading

0 comments on commit 7974ebc

Please sign in to comment.