From c55d01a8744ed705869e8de527522e4bf9eaae00 Mon Sep 17 00:00:00 2001 From: Giovanni Sollazzo Date: Wed, 9 Nov 2022 16:20:53 +0100 Subject: [PATCH 01/21] AIDEM Bid Adapter --- modules/aidemBidAdapter.js | 691 +++++++++++++++++++++++++++++++++++++ modules/aidemBidAdapter.md | 186 ++++++++++ 2 files changed, 877 insertions(+) create mode 100644 modules/aidemBidAdapter.js create mode 100644 modules/aidemBidAdapter.md diff --git a/modules/aidemBidAdapter.js b/modules/aidemBidAdapter.js new file mode 100644 index 00000000000..e817d70b980 --- /dev/null +++ b/modules/aidemBidAdapter.js @@ -0,0 +1,691 @@ +import { + _each, + contains, + deepAccess, + deepSetValue, + getDNT, + isInteger, + logError, + logInfo, + isBoolean, + isStr +} from '../src/utils.js'; +import {config} from '../src/config.js'; +import {BANNER, VIDEO} from '../src/mediaTypes.js'; +import {registerBidder} from '../src/adapters/bidderFactory.js'; +import {getRefererInfo} from '../src/refererDetection.js'; +import {ajax} from '../src/ajax.js'; + +const BIDDER_CODE = 'aidem'; +const BASE_URL = 'https://zero.aidemsrv.com'; +const LOCAL_BASE_URL = 'http://127.0.0.1:8787'; + +const AVAILABLE_CURRENCIES = ['USD']; +const DEFAULT_CURRENCY = ['USD']; // NOTE - USD is the only supported currency right now; Hardcoded for bids +const SUPPORTED_MEDIA_TYPES = [BANNER, VIDEO]; +const REQUIRED_VIDEO_PARAMS = [ 'mimes', 'protocols', 'context' ]; + +export const ERROR_CODES = { + BID_SIZE_INVALID_FORMAT: 1, + BID_SIZE_NOT_INCLUDED: 2, + PROPERTY_NOT_INCLUDED: 3, + SITE_ID_INVALID_VALUE: 4, + MEDIA_TYPE_NOT_SUPPORTED: 5, +}; + +const endpoints = { + request: `${BASE_URL}/bid/request`, + notice: { + win: `${BASE_URL}/notice/win`, + timeout: `${BASE_URL}/notice/timeout`, + error: `${BASE_URL}/notice/error`, + } +} + +export function setEndPoints(env = null, path = '', mediaType = BANNER) { + switch (env) { + case 'local': + endpoints.request = mediaType === BANNER ? `${LOCAL_BASE_URL}${path}/bid/request` : `${LOCAL_BASE_URL}${path}/bid/videorequest` + endpoints.notice.win = `${LOCAL_BASE_URL}${path}/notice/win` + endpoints.notice.error = `${LOCAL_BASE_URL}${path}/notice/error` + endpoints.notice.timeout = `${LOCAL_BASE_URL}${path}/notice/timeout` + break; + case 'main': + endpoints.request = mediaType === BANNER ? `${BASE_URL}${path}/bid/request` : `${BASE_URL}${path}/bid/videorequest` + endpoints.notice.win = `${BASE_URL}${path}/notice/win` + endpoints.notice.error = `${BASE_URL}${path}/notice/error` + endpoints.notice.timeout = `${BASE_URL}${path}/notice/timeout` + break; + } + return endpoints +} + +let ortb2 = {} + +config.getConfig('aidem', function (config) { + if (config.aidem.env) { setEndPoints(config.aidem.env, config.aidem.path, config.aidem.mediaType) } +}) + +config.getConfig('ortb2', function (config) { + ortb2 = Object.assign({}, ortb2, config.ortb2) +}) + +// AIDEM Custom FN +function recur(obj) { + var result = {}; var _tmp; + for (var i in obj) { + // enabledPlugin is too nested, also skip functions + if (!(i === 'enabledPlugin' || typeof obj[i] === 'function')) { + if (typeof obj[i] === 'object') { + // get props recursively + _tmp = recur(obj[i]); + // if object is not {} + if (Object.keys(_tmp).length) { + result[i] = _tmp; + } + } else { + // string, number or boolean + result[i] = obj[i]; + } + } + } + return result; +} + +/** + * Determines whether or not the given object is valid size format. + * + * @param {*} size The object to be validated. + * @return {boolean} True if this is a valid size format, and false otherwise. + */ +function isValidSize(size) { + return Array.isArray(size) && size.length === 2 && isInteger(size[0]) && isInteger(size[1]); +} + +/** + * Determines whether or not the given size object is an element of the size + * array. + * + * @param {array} sizeArray The size array. + * @param {object} size The size object. + * @return {boolean} True if the size object is an element of the size array, and false + * otherwise. + */ +function includesSize(sizeArray = [], size = []) { + if (isValidSize(sizeArray)) { + return sizeArray[0] === size[0] && sizeArray[1] === size[1]; + } + for (let i = 0; i < sizeArray.length; i++) { + if (sizeArray[i][0] === size[0] && sizeArray[i][1] === size[1]) { + return true; + } + } + return false; +} + +// ================================================================================= +function getConnectionType() { + const connection = navigator.connection || navigator.webkitConnection; + if (!connection) { + return 0; + } + switch (connection.type) { + case 'ethernet': + return 1; + case 'wifi': + return 2; + case 'cellular': + switch (connection.effectiveType) { + case 'slow-2g': + return 4; + case '2g': + return 4; + case '3g': + return 5; + case '4g': + return 6; + case '5g': + return 7; + default: + return 3; + } + default: + return 0; + } +} + +function getDevice() { + const language = navigator.language || navigator.browserLanguage || navigator.userLanguage || navigator.systemLanguage; + return { + ua: navigator.userAgent, + dnt: getDNT() ? 1 : 0, + language: language, + connectiontype: getConnectionType(), + screen_width: screen.width, + screen_height: screen.height + }; +} + +function getRegs() { + let regs = {}; + const consentManagement = config.getConfig('consentManagement') + const coppa = config.getConfig('coppa') + if (consentManagement && !!(consentManagement.gdpr)) { + deepSetValue(regs, 'gdpr', !!consentManagement.gdpr); + } + if (consentManagement && deepAccess(consentManagement, 'usp.cmpApi') === 'static') { + deepSetValue(regs, 'us_privacy', deepAccess(consentManagement, 'usp.consentData.getUSPData.uspString')); + } + if (isBoolean(coppa)) { + deepSetValue(regs, 'coppa', !!coppa); + } + + return regs; +} + +/** + * Returns bidder request page url. + * + * @param {Object} bidderRequest + * @return {string} + */ +function getPageUrl(bidderRequest) { + return bidderRequest?.refererInfo?.page +} + +function buildWonBidNotice(bid) { + const winNotice = { + adId: bid.adId, + adUnitCode: bid.adUnitCode, + creativeId: bid.creativeId, + cpm: bid.cpm, + netRevenue: bid.netRevenue, + adserverTargeting: bid.adserverTargeting, + auctionId: bid.auctionId, + currency: bid.currency, + mediaType: bid.mediaType, + size: bid.size, + width: bid.width, + height: bid.height, + status: bid.status, + transactionId: bid.transactionId, + ttl: bid.ttl, + requestTimestamp: bid.requestTimestamp, + responseTimestamp: bid.responseTimestamp, + metrics: {} + } + + if (bid.metrics && typeof bid.metrics.getMetrics === 'function') { + const metrics = bid.metrics.getMetrics() + deepSetValue(winNotice.metrics, 'requestBids.validate', metrics['requestBids.validate']) + deepSetValue(winNotice.metrics, 'requestBids.makeRequests', metrics['requestBids.makeRequests']) + deepSetValue(winNotice.metrics, 'requestBids.total', metrics['requestBids.total']) + deepSetValue(winNotice.metrics, 'requestBids.callBids', metrics['requestBids.callBids']) + deepSetValue(winNotice.metrics, 'adapter.client.validate', metrics['adapter.client.validate']) + deepSetValue(winNotice.metrics, 'adapter.client.buildRequests', metrics['adapter.client.buildRequests']) + deepSetValue(winNotice.metrics, 'adapter.client.total', metrics['adapter.client.total']) + deepSetValue(winNotice.metrics, 'adapter.client.net', metrics['adapter.client.net']) + deepSetValue(winNotice.metrics, 'adapter.client.interpretResponse', metrics['adapter.client.interpretResponse']) + deepSetValue(winNotice.metrics, 'addBidResponse.validate', metrics['addBidResponse.validate']) + deepSetValue(winNotice.metrics, 'addBidResponse.total', metrics['addBidResponse.total']) + deepSetValue(winNotice.metrics, 'render.pending', metrics['render.pending']) + deepSetValue(winNotice.metrics, 'render.e2e', metrics['render.e2e']) + } + + return winNotice +} + +// Called for every bid that has timed out +function buildTimeoutNotice(prebidTimeoutBids) { + const timeoutNotice = { + bids: [] + } + _each(prebidTimeoutBids, function (bid) { + const notice = { + adUnitCode: bid.adUnitCode, + auctionId: bid.auctionId, + bidId: bid.bidId, + bidderRequestId: bid.bidderRequestId, + transactionId: bid.transactionId, + mediaTypes: bid.mediaTypes, + metrics: { }, + timeout: bid.timeout, + } + + if (bid.metrics && typeof bid.metrics.getMetrics === 'function') { + const metrics = bid.metrics.getMetrics() + deepSetValue(notice.metrics, 'requestBids.validate', metrics['requestBids.validate']) + deepSetValue(notice.metrics, 'requestBids.makeRequests', metrics['requestBids.makeRequests']) + deepSetValue(notice.metrics, 'requestBids.total', metrics['requestBids.total']) + deepSetValue(notice.metrics, 'requestBids.callBids', metrics['requestBids.callBids']) + deepSetValue(notice.metrics, 'adapter.client.validate', metrics['adapter.client.validate']) + deepSetValue(notice.metrics, 'adapter.client.buildRequests', metrics['adapter.client.buildRequests']) + deepSetValue(notice.metrics, 'adapter.client.total', metrics['adapter.client.total']) + deepSetValue(notice.metrics, 'adapter.client.net', metrics['adapter.client.net']) + deepSetValue(notice.metrics, 'adapter.client.interpretResponse', metrics['adapter.client.interpretResponse']) + } + + timeoutNotice.bids.push(notice) + }) + + return timeoutNotice +} + +function buildErrorNotice(prebidErrorResponse) { + const errorNotice = { + message: `Prebid.js: Server call for ${prebidErrorResponse.bidderCode} failed.`, + url: encodeURIComponent(getPageUrl(prebidErrorResponse)), + auctionId: prebidErrorResponse.auctionId, + bidderRequestId: prebidErrorResponse.bidderRequestId, + metrics: {} + } + if (prebidErrorResponse.metrics && typeof prebidErrorResponse.metrics.getMetrics === 'function') { + const metrics = prebidErrorResponse.metrics.getMetrics() + deepSetValue(errorNotice.metrics, 'requestBids.validate', metrics['requestBids.validate']) + deepSetValue(errorNotice.metrics, 'requestBids.makeRequests', metrics['requestBids.makeRequests']) + deepSetValue(errorNotice.metrics, 'requestBids.total', metrics['requestBids.total']) + deepSetValue(errorNotice.metrics, 'requestBids.callBids', metrics['requestBids.callBids']) + deepSetValue(errorNotice.metrics, 'adapter.client.validate', metrics['adapter.client.validate']) + deepSetValue(errorNotice.metrics, 'adapter.client.buildRequests', metrics['adapter.client.buildRequests']) + deepSetValue(errorNotice.metrics, 'adapter.client.total', metrics['adapter.client.total']) + deepSetValue(errorNotice.metrics, 'adapter.client.net', metrics['adapter.client.net']) + deepSetValue(errorNotice.metrics, 'adapter.client.interpretResponse', metrics['adapter.client.interpretResponse']) + } + return errorNotice +} + +/** + * Get One size from Size Array + * [[250,350]] -> [250, 350] + * [250, 350] -> [250, 350] + * @param {array} sizes array of sizes + */ +function getFirstSize(sizes = []) { + if (isValidSize(sizes)) { + return sizes; + } else if (isValidSize(sizes[0])) { + return sizes[0]; + } + + return false; +} + +function hasValidFloor(obj) { + if (!obj) return false + const hasValue = !isNaN(Number(obj.value)) + const hasCurrency = contains(AVAILABLE_CURRENCIES, obj.currency) + return hasValue && hasCurrency +} + +function getMediaType(bidRequest) { + if ((bidRequest.mediaTypes && bidRequest.mediaTypes.hasOwnProperty('video')) || bidRequest.params.hasOwnProperty('video')) { return VIDEO } + return BANNER +} + +function getPrebidRequestFields(bidderRequest, bidRequests) { + const payload = {} + // Base Payload Data + deepSetValue(payload, 'id', bidderRequest.auctionId); + // Impressions + setPrebidImpressionObject(bidRequests, payload) + // Device + deepSetValue(payload, 'device', getDevice()) + // Timeout + deepSetValue(payload, 'tmax', bidderRequest.timeout); + // Currency + deepSetValue(payload, 'cur', DEFAULT_CURRENCY); + // Timezone + deepSetValue(payload, 'tz', new Date().getTimezoneOffset()); + // Privacy Regs + deepSetValue(payload, 'regs', getRegs()); + // Site + setPrebidSiteObject(bidderRequest, payload) + // Environment + setPrebidRequestEnvironment(payload) + // AT auction type + deepSetValue(payload, 'at', 1); + // User + payload.user = {}; + + return payload +} + +function setPrebidImpressionObject(bidRequests, payload) { + payload.imp = []; + payload.mediaTypes = [] + _each(bidRequests, function (bidRequest) { + const impressionObject = {}; + // Placement or ad tag used to initiate the auction + deepSetValue(impressionObject, 'id', bidRequest.bidId); + // Site id + deepSetValue(impressionObject, 'siteId', deepAccess(bidRequest, 'params.siteId')); + // Tag id + deepSetValue(impressionObject, 'tid', deepAccess(bidRequest, 'transactionId')); + const mediaType = getMediaType(bidRequest) + if (!payload.mediaTypes.includes(mediaType)) { + payload.mediaTypes.push(mediaType) + } + switch (mediaType) { + case 'banner': + setPrebidImpressionObjectBanner(bidRequest, impressionObject) + break; + case 'video': + setPrebidImpressionObjectVideo(bidRequest, impressionObject) + break; + } + + // Floor (optional) + setPrebidImpressionObjectFloor(bidRequest, impressionObject) + + impressionObject.imp_ext = {}; + + payload.imp.push(impressionObject); + }); +} + +function setPrebidSiteObject(bidderRequest, payload) { + deepSetValue(payload, 'site.domain', deepAccess(bidderRequest, 'refererInfo.domain')); + deepSetValue(payload, 'site.page', deepAccess(bidderRequest, 'refererInfo.page')); + deepSetValue(payload, 'site.referer', deepAccess(bidderRequest, 'refererInfo.ref')); + deepSetValue(payload, 'site.cat', deepAccess(ortb2, 'site.cat')); + deepSetValue(payload, 'site.sectioncat', deepAccess(ortb2, 'site.sectioncat')); + deepSetValue(payload, 'site.keywords', deepAccess(ortb2, 'site.keywords')); + deepSetValue(payload, 'site.site_ext', deepAccess(ortb2, 'site.ext')); // see https://docs.prebid.org/features/firstPartyData.html +} + +function setPrebidRequestEnvironment(payload) { + const __navigator = JSON.parse(JSON.stringify(recur(navigator))); + delete __navigator.plugins; + deepSetValue(payload, 'environment.ri', getRefererInfo()); + deepSetValue(payload, 'environment.hl', window.history.length); + deepSetValue(payload, 'environment.nav', __navigator); + deepSetValue(payload, 'environment.inp.euc', window.encodeURIComponent.name === 'encodeURIComponent' && typeof window.encodeURIComponent.prototype === 'undefined'); + deepSetValue(payload, 'environment.inp.eu', window.encodeURI.name === 'encodeURI' && typeof window.encodeURI.prototype === 'undefined'); + deepSetValue(payload, 'environment.inp.js', window.JSON.stringify.name === 'stringify' && typeof window.JSON.stringify.prototype === 'undefined'); + deepSetValue(payload, 'environment.inp.jp', window.JSON.parse.name === 'parse' && typeof window.JSON.parse.prototype === 'undefined'); + deepSetValue(payload, 'environment.inp.ofe', window.Object.fromEntries.name === 'fromEntries' && typeof window.Object.fromEntries.prototype === 'undefined'); + deepSetValue(payload, 'environment.inp.oa', window.Object.assign.name === 'assign' && typeof window.Object.assign.prototype === 'undefined'); +} + +function setPrebidImpressionObjectFloor(bidRequest, impressionObject) { + const floor = deepAccess(bidRequest, 'params.floor') + if (hasValidFloor(floor)) { + deepSetValue(impressionObject, 'floor.value', floor.value) + deepSetValue(impressionObject, 'floor.currency', floor.currency) + } +} + +function setPrebidImpressionObjectBanner(bidRequest, impressionObject) { + deepSetValue(impressionObject, 'mediatype', BANNER); + deepSetValue(impressionObject, 'banner.topframe', 1); + deepSetValue(impressionObject, 'banner.format', []); + _each(bidRequest.mediaTypes.banner.sizes, function (bannerFormat) { + const format = {}; + deepSetValue(format, 'w', bannerFormat[0]); + deepSetValue(format, 'h', bannerFormat[1]); + deepSetValue(format, 'format_ext', {}); + impressionObject.banner.format.push(format); + }); +} + +function setPrebidImpressionObjectVideo(bidRequest, impressionObject) { + deepSetValue(impressionObject, 'mediatype', VIDEO); + deepSetValue(impressionObject, 'video.format', []); + deepSetValue(impressionObject, 'video.mimes', bidRequest.mediaTypes.video.mimes); + deepSetValue(impressionObject, 'video.minDuration', bidRequest.mediaTypes.video.minduration); + deepSetValue(impressionObject, 'video.maxDuration', bidRequest.mediaTypes.video.maxduration); + deepSetValue(impressionObject, 'video.protocols', bidRequest.mediaTypes.video.protocols); + deepSetValue(impressionObject, 'video.context', bidRequest.mediaTypes.video.context); + deepSetValue(impressionObject, 'video.playbackmethod', bidRequest.mediaTypes.video.playbackmethod); + deepSetValue(impressionObject, 'skip', bidRequest.mediaTypes.video.skip); + deepSetValue(impressionObject, 'skipafter', bidRequest.mediaTypes.video.skipafter); + deepSetValue(impressionObject, 'video.pos', bidRequest.mediaTypes.video.pos); + _each(bidRequest.mediaTypes.video.playerSize, function (videoPlayerSize) { + const format = {}; + deepSetValue(format, 'w', videoPlayerSize[0]); + deepSetValue(format, 'h', videoPlayerSize[1]); + deepSetValue(format, 'format_ext', {}); + impressionObject.video.format.push(format); + }); +} + +function getPrebidResponseBidObject(openRTBResponseBidObject) { + const prebidResponseBidObject = {}; + // Common properties + deepSetValue(prebidResponseBidObject, 'requestId', openRTBResponseBidObject.id); + deepSetValue(prebidResponseBidObject, 'cpm', parseFloat(openRTBResponseBidObject.price)); + deepSetValue(prebidResponseBidObject, 'currency', openRTBResponseBidObject.currency ? openRTBResponseBidObject.currency.toUpperCase() : DEFAULT_CURRENCY); + deepSetValue(prebidResponseBidObject, 'width', openRTBResponseBidObject.w); + deepSetValue(prebidResponseBidObject, 'height', openRTBResponseBidObject.h); + deepSetValue(prebidResponseBidObject, 'creativeId', openRTBResponseBidObject.adid); + deepSetValue(prebidResponseBidObject, 'dealId', openRTBResponseBidObject.deal) + deepSetValue(prebidResponseBidObject, 'netRevenue', openRTBResponseBidObject.isNet ? openRTBResponseBidObject.isNet : false); + deepSetValue(prebidResponseBidObject, 'ttl', 300); + + if (openRTBResponseBidObject.mediatype === VIDEO) { + logInfo('bidObject.mediatype == VIDEO'); + deepSetValue(prebidResponseBidObject, 'mediaType', VIDEO); + deepSetValue(prebidResponseBidObject, 'vastUrl', openRTBResponseBidObject.adm); + } else { + logInfo('bidObject.mediatype == BANNER'); + deepSetValue(prebidResponseBidObject, 'mediaType', BANNER); + deepSetValue(prebidResponseBidObject, 'ad', openRTBResponseBidObject.adm); + } + setPrebidResponseBidObjectMeta(prebidResponseBidObject, openRTBResponseBidObject) + return prebidResponseBidObject +} + +function setPrebidResponseBidObjectMeta(prebidResponseBidObject, openRTBResponseBidObject) { + deepSetValue(prebidResponseBidObject, 'meta.advertiserDomains', openRTBResponseBidObject.adomain && Array.isArray(openRTBResponseBidObject.adomain) ? openRTBResponseBidObject.adomain : []); +} + +function hasValidMediaType(bidRequest) { + const supported = hasBannerMediaType(bidRequest) || hasVideoMediaType(bidRequest) + if (!supported) { + logError('AIDEM Bid Adapter: media type not supported', { bidder: BIDDER_CODE, code: ERROR_CODES.MEDIA_TYPE_NOT_SUPPORTED }); + } + return supported +} + +function hasBannerMediaType(bidRequest) { + return !!deepAccess(bidRequest, 'mediaTypes.banner') +} + +function hasVideoMediaType(bidRequest) { + return !!deepAccess(bidRequest, 'mediaTypes.video') +} + +function hasValidBannerMediaType(bidRequest) { + const sizes = deepAccess(bidRequest, 'mediaTypes.banner.sizes') + if (!sizes) { + logError('AIDEM Bid Adapter: media type sizes missing', { bidder: BIDDER_CODE, code: ERROR_CODES.PROPERTY_NOT_INCLUDED }); + return false; + } + return true +} + +function hasValidVideoMediaType(bidRequest) { + const sizes = deepAccess(bidRequest, 'mediaTypes.video.playerSize'); + if (!sizes) { + logError('AIDEM Bid Adapter: media type playerSize missing', { bidder: BIDDER_CODE, code: ERROR_CODES.PROPERTY_NOT_INCLUDED }); + return false; + } + return true +} + +function hasValidBannerBidderParameters(bidRequest) { + const mediaTypesSizes = deepAccess(bidRequest, 'mediaTypes.banner.sizes'); + const size = deepAccess(bidRequest, 'params.banner.size'); + const flatten = getFirstSize(size); + if (size && !flatten) { + logError('AIDEM Bid Adapter: size has invalid format.', { bidder: BIDDER_CODE, code: ERROR_CODES.BID_SIZE_INVALID_FORMAT }); + return false; + } + + if (size && !(includesSize(mediaTypesSizes, flatten))) { + logError('AIDEM Bid Adapter: bidder banner size is not included in ad unit banner sizes.', { bidder: BIDDER_CODE, code: ERROR_CODES.BID_SIZE_NOT_INCLUDED }); + return false; + } + + return true +} + +function hasValidVideoBidderParameters(bidRequest) { + const mediaTypesSizes = deepAccess(bidRequest, 'mediaTypes.video.playerSize'); + const size = deepAccess(bidRequest, 'params.video.size'); + const flatten = getFirstSize(size); + if (size && !flatten) { + logError('AIDEM Bid Adapter: size has invalid format.', { bidder: BIDDER_CODE, code: ERROR_CODES.BID_SIZE_INVALID_FORMAT }); + return false; + } + if (size && !(includesSize(mediaTypesSizes, size))) { + logError('AIDEM Bid Adapter: bidder banner size is not included in ad unit playerSize.', { bidder: BIDDER_CODE, code: ERROR_CODES.BID_SIZE_NOT_INCLUDED }); + return false; + } + + return hasValidVideoParameters(bidRequest); +} + +function hasValidVideoParameters(bidRequest) { + let valid = true + const adUnitsParameters = deepAccess(bidRequest, 'mediaTypes.video'); + const bidderParameter = deepAccess(bidRequest, 'params.video'); + for (let property of REQUIRED_VIDEO_PARAMS) { + const hasAdUnitParameter = adUnitsParameters.hasOwnProperty(property) + const hasBidderParameter = bidderParameter && bidderParameter.hasOwnProperty(property) + if (!hasAdUnitParameter && !hasBidderParameter) { + logError(`AIDEM Bid Adapter: ${property} is not included in either the adunit or params level`, { bidder: BIDDER_CODE, code: ERROR_CODES.PROPERTY_NOT_INCLUDED }); + valid = false + } + } + + return valid +} + +function hasValidParameters(bidRequest) { + // Assigned from AIDEM to a publisher website + const siteId = deepAccess(bidRequest, 'params.siteId'); + if (!isStr(siteId)) { + logError('AIDEM Bid Adapter: siteId must valid string', { bidder: BIDDER_CODE, code: ERROR_CODES.SITE_ID_INVALID_VALUE }); + return false; + } + + return true +} + +export const spec = { + code: BIDDER_CODE, + supportedMediaTypes: SUPPORTED_MEDIA_TYPES, + /** + * Determines whether or not the given bid request is valid. + * + * @param {BidRequest} bidRequest The bid params to validate. + * @return boolean True if this is a valid bid, and false otherwise. + */ + isBidRequestValid: function(bidRequest) { + logInfo('bid: ', bidRequest); + + // check if request has valid mediaTypes + if (!hasValidMediaType(bidRequest)) return false + + // check if request has valid media type parameters at adUnit level + if (hasBannerMediaType(bidRequest) && !hasValidBannerMediaType(bidRequest)) { + return false + } + if (hasVideoMediaType(bidRequest) && !hasValidVideoMediaType(bidRequest)) { + return false + } + + // check if request has valid media type parameters at adUnit level + if (hasBannerMediaType(bidRequest) && !hasValidBannerBidderParameters(bidRequest)) { + return false + } + if (hasVideoMediaType(bidRequest) && !hasValidVideoBidderParameters(bidRequest)) { + return false + } + + return hasValidParameters(bidRequest) + }, + + /** + * Make a server request from the list of BidRequests. + * + * @param validBidRequests[] - An array of bidRequest objects, one for each AdUnit that your module is involved in + * @param bidderRequest - The master bidRequest object. This object is useful because it carries a couple of bid parameters that are global to all the bids + * @return ServerRequest Info describing the request to the server. + */ + buildRequests: function(validBidRequests, bidderRequest) { + logInfo('validBidRequests: ', validBidRequests); + logInfo('bidderRequest: ', bidderRequest); + const prebidRequest = getPrebidRequestFields(bidderRequest, validBidRequests) + const payloadString = JSON.stringify(prebidRequest); + + return { + method: 'POST', + url: endpoints.request, + data: payloadString, + options: { + withCredentials: true + } + }; + }, + + /** + * Unpack the response from the server into a list of bids. + * + * @param {ServerResponse} serverResponse A successful response from the server. + * @return {Bid[]} An array of bids which were nested inside the server. + */ + interpretResponse: function (serverResponse) { + const bids = []; + logInfo('serverResponse: ', serverResponse); + _each(serverResponse.body.seatbid, function (bidSeatObject) { + logInfo('bidSeatObject: ', bidSeatObject); + _each(bidSeatObject.bid, function (bidObject) { + logInfo('bidObject: ', bidObject); + if (!bidObject.price || !bidObject.adm) { + return; + } + logInfo('CPM OK'); + const bid = getPrebidResponseBidObject(bidObject) + bids.push(bid); + }); + }); + + return bids; + }, + + /** + * Register bidder specific code, which will execute if a bid from this bidder won the auction + * @param {Bid} bid that won the auction + */ + onBidWon: function(bid) { + // Bidder specific code + logInfo('onBidWon bid: ', bid); + const notice = buildWonBidNotice(bid) + ajax(endpoints.notice.win, null, JSON.stringify(notice), { method: 'POST', withCredentials: true }); + }, + + /** + * Register bidder specific code, which will execute if bidder timed out after an auction + * + * @param {Array} data timeout specific data + */ + onTimeout: (data) => { + if (Array.isArray(data)) { + const payload = buildTimeoutNotice(data) + const payloadString = JSON.stringify(payload); + ajax(endpoints.notice.timeout, null, payloadString, { method: 'POST', withCredentials: true }); + } + }, + + /** + * Register bidder specific code, which will execute if the bidder responded with an error + */ + onBidderError: function({ bidderRequest }) { + // Bidder specific code + const notice = buildErrorNotice(bidderRequest) + ajax(endpoints.notice.error, null, JSON.stringify(notice), { method: 'POST', withCredentials: true }); + }, +} +registerBidder(spec); diff --git a/modules/aidemBidAdapter.md b/modules/aidemBidAdapter.md new file mode 100644 index 00000000000..7d397239bc1 --- /dev/null +++ b/modules/aidemBidAdapter.md @@ -0,0 +1,186 @@ +# Overview + +``` +name: AIDEM Adapter +type: Bidder Adapter +support: prebid@aidem.com +biddercode: aidem +``` + +# Description +This module connects publishers to AIDEM demand. + +This module is GDPR and CCPA compliant, and no 3rd party userIds are allowed. + + +## Global Bid Params +| Name | Scope | Description | Example | Type | +|---------------|----------|---------------------|---------------|----------| +| `siteId` | required | Unique site ID | `'ABCDEF'` | `String` | + + +### Banner Bid Params +| Name | Scope | Description | Example | Type | +|------------|----------|--------------------------|---------------------------|---------| +| `sizes` | required | List of the sizes wanted | `[[300, 250], [300,600]]` | `Array` | + + +### Video Bid Params +| Name | Scope | Description | Example | Type | +|---------------|----------|-----------------------------------------|-----------------|-----------| +| `context` | required | One of instream, outstream, adpod | `'instream'` | `String` | +| `playerSize` | required | Width and height of the player | `'[640, 480]'` | `Array` | +| `maxduration` | required | Maximum video ad duration, in seconds | `30` | `Integer` | +| `minduration` | required | Minimum video ad duration, in seconds | `5` | `Integer` | +| `mimes` | required | List of the content MIME types supported by the player | `["video/mp4"]` | `Array` | +| `protocols` | required | An array of supported video protocols. At least one supported protocol must be specified, where: `2` = VAST 2.0 `3` = VAST 3.0 `5` = VAST 2.0 wrapper `6` = VAST 3.0 wrapper | `2` | `Array` | + + +### Additional Config +| Name | Scope | Description | Example | Type | +|---------------------|----------|---------------------------------------------------------|---------|-----------| +| `coppa` | optional | Child Online Privacy Protection Act | `true` | `Boolean` | +| `consentManagement` | optional | [Consent Management Object](#consent-management-object) | `{}` | `Object` | + + +### Consent Management Object +| Name | Scope | Description | Example | Type | +|--------|----------|--------------------------------------------------------------------------------------------------|---------|----------| +| `gdpr` | optional | GDPR Object see [Prebid.js doc](https://docs.prebid.org/dev-docs/modules/consentManagement.html) | `{}` | `Object` | +| `usp` | optional | USP Object see [Prebid.js doc](https://docs.prebid.org/dev-docs/modules/consentManagementUsp.html) | `{}` | `Object` | + + +### Example Banner ad unit +```javascript +var adUnits = [{ + code: 'banner-prebid-test-site', + mediaTypes: { + banner: { + sizes: [ + [300, 600], + [300, 250] + ] + } + }, + bids: [{ + bidder: 'aidem', + params: { + siteId: 'prebid-test-site', + }, + }] +}]; +``` + +### Example Video ad unit +```javascript +var adUnits = [{ + code: 'video-prebid-test-site', + mediaTypes: { + video: { + context: 'instream', + playerSize: [640, 480], + maxduration: 30, + minduration: 5, + mimes: ["video/mp4"], + protocols: 2 + } + }, + bids: [{ + bidder: 'aidem', + params: { + siteId: 'prebid-test-site', + }, + }] +}]; +``` + +### Example GDPR Consent Management +```javascript +var pbjs = pbjs || {}; +pbjs.que = pbjs.que || []; + +pbjs.que.push(function (){ + pbjs.setConfig({ + consentManagement: { + gdpr:{ + cmpApi: 'iab' + } + } + }); +}) +``` + + +### Example USP Consent Management +```javascript +var pbjs = pbjs || {}; +pbjs.que = pbjs.que || []; + +pbjs.que.push(function (){ + pbjs.setConfig({ + consentManagement: { + usp:{ + cmpApi: 'static', + consentData:{ + getUSPData:{ + uspString: '1YYY' + } + } + } + } + }); +}) +``` + + +### Setting First Party Data (FPD) +```javascript +var pbjs = pbjs || {}; +pbjs.que = pbjs.que || []; + +pbjs.que.push(function (){ + pbjs.setConfig({ + ortb2: { + site: { + cat: ['IAB2'], + sectioncat: ['IAB2-2'], + keywords: 'power tools, drills' + }, + } + }); +}) +``` + +### Supported Media Types +| Type | Support | +|--------|--------------------------------------------------------------------| +| Banner | Support all [AIDEM Sizes](https://kb.aidem.com/ssp/lists/adsizes/) | +| Video | Support all [AIDEM Sizes](https://kb.aidem.com/ssp/lists/adsizes/) | + + +# Setup / Dev Guide +```shell +nvm use + +npm install + +gulp build --modules=aidemBidAdapter + +gulp serve --modules=aidemBidAdapter + +# Open a chrome browser with no ad blockers enabled, and paste in this URL. The `pbjs_debug=true` is needed if you want to enable `loggerInfo` output on the `console` tab of Chrome Developer Tools. +http://localhost:9999/integrationExamples/gpt/hello_world.html?pbjs_debug=true +``` + +If you need to run the tests suite but do *not* want to have to build the full adapter and serve it, simply run: +```shell +gulp test --file "test/spec/modules/aidemBidAdapter_spec.js" +``` + + +For video: gulp serve --modules=aidemBidAdapter,dfpAdServerVideo + +# FAQs +### How do I view AIDEM bid request? +Navigate to a page where AIDEM is setup to bid. In the network tab, +search for requests to `zero.aidemsrv.com/bid/request`. \ No newline at end of file From fc359c172d6d6fc712c641e41d103c48debabd9e Mon Sep 17 00:00:00 2001 From: Giovanni Sollazzo Date: Thu, 10 Nov 2022 10:28:33 +0100 Subject: [PATCH 02/21] Added _spec.js --- test/spec/modules/aidemBidAdapter_spec.js | 785 ++++++++++++++++++++++ 1 file changed, 785 insertions(+) create mode 100644 test/spec/modules/aidemBidAdapter_spec.js diff --git a/test/spec/modules/aidemBidAdapter_spec.js b/test/spec/modules/aidemBidAdapter_spec.js new file mode 100644 index 00000000000..ca542292be2 --- /dev/null +++ b/test/spec/modules/aidemBidAdapter_spec.js @@ -0,0 +1,785 @@ +import {expect} from 'chai'; +import {setEndPoints, spec} from 'modules/aidemBidAdapter.js'; +import * as utils from '../../../src/utils'; +import {_each, deepSetValue} from '../../../src/utils'; +import {server} from '../../mocks/xhr'; +import {config} from '../../../src/config'; +import {NATIVE} from '../../../src/mediaTypes.js'; + +// TODO implement more extensive VALID_BIDS +// Full banner + Full Video + Basic Banner + Basic Video +const VALID_BIDS = [ + { + bidder: 'aidem', + params: { + siteId: '301491', + placementId: 13144370, + }, + mediaTypes: { + banner: { + sizes: [[300, 250], [300, 600]], + } + }, + }, + { + bidder: 'aidem', + params: { + siteId: '301491', + placementId: 13144370, + }, + mediaTypes: { + video: { + context: 'instream', + minduration: 7, + maxduration: 30, + playerSize: [640, 480], + mimes: ['video/mp4'], + protocols: [2] + } + }, + }, +] + +// TODO add some invalid requests +const INVALID_BIDS = [ + { + bidder: 'aidem', + params: { + siteId: '3014912' + } + }, + { + bidder: 'aidem', + mediaTypes: { + banner: { + sizes: [[300, 250], [300, 600]], + } + }, + params: { + siteId: undefined + } + }, + { + bidder: 'aidem', + params: { + siteId: '3014912', + member: '301e4912' + } + }, + { + bidder: 'aidem', + params: { + siteId: '3014912', + invCode: '3014912' + } + }, + { + bidder: 'aidem', + mediaType: NATIVE, + params: { + siteId: '3014912' + } + }, + { + bidder: 'aidem', + mediaTypes: { + banner: {} + }, + }, + { + bidder: 'aidem', + mediaTypes: { + banner: { + sizes: [[300, 250], [300, 600]], + } + }, + params: { + siteId: '301491', + placementId: 13144370, + banner: { + size: [250, 250] + } + }, + }, + { + bidder: 'aidem', + mediaTypes: { + banner: { + sizes: [[300, 250], [300, 600]], + } + }, + params: { + siteId: '301491', + placementId: 13144370, + banner: { + size: '250x250' + } + }, + }, + { + bidder: 'aidem', + mediaTypes: { + video: { + placement: 1, + minduration: 7, + maxduration: 30, + mimes: ['video/mp4'], + protocols: [2] + } + }, + params: { + siteId: '301491', + placementId: 13144370, + }, + }, + { + bidder: 'aidem', + mediaTypes: { + video: { + minduration: 7, + maxduration: 30, + playerSize: [640, 480], + mimes: ['video/mp4'], + protocols: [2] + } + }, + params: { + siteId: '301491', + placementId: 13144370, + }, + }, + { + bidder: 'aidem', + mediaTypes: { + video: { + minduration: 7, + maxduration: 30, + playerSize: [640, 480], + mimes: ['video/mp4'], + protocols: [2], + placement: 1 + } + }, + params: { + siteId: '301491', + placementId: 13144370, + video: { + size: [480, 40] + } + }, + }, +] + +const DEFAULT_VALID_BANNER_REQUESTS = [ + { + adUnitCode: 'test-div', + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + bidId: '22c4871113f461', + bidder: 'aidem', + bidderRequestId: '15246a574e859f', + mediaTypes: { + banner: { + sizes: [ + [ 300, 250 ], + [ 300, 600 ] + ] + } + }, + params: { + siteId: 1, + placementId: 13144370 + }, + src: 'client', + transactionId: '54a58774-7a41-494e-9aaf-fa7b79164f0c' + } +]; + +const DEFAULT_VALID_VIDEO_REQUESTS = [ + { + adUnitCode: 'test-div', + auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', + bidId: '22c4871113f461', + bidder: 'aidem', + bidderRequestId: '15246a574e859f', + mediaTypes: { + video: { + minduration: 7, + maxduration: 30, + playerSize: [640, 480], + mimes: ['video/mp4'], + protocols: [2] + } + }, + params: { + siteId: 1, + placementId: 13144370 + }, + src: 'client', + transactionId: '54a58774-7a41-494e-9aaf-fa7b79164f0c' + } +]; + +const VALID_BIDDER_REQUEST = { + auctionId: '6e9b46c3-65a8-46ea-89f4-c5071110c85c', + bidderCode: 'aidem', + bidderRequestId: '170ea5d2b1d073', + refererInfo: { + page: 'test-page', + domain: 'test-domain', + ref: 'test-referer' + }, +} + +// Add mediatype +const SERVER_RESPONSE_BANNER = { + body: { + id: 'efa1930a-bc3e-4fd0-8368-08bc40236b4f', + seatbid: [ + { + bid: [ + // BANNER + { + 'id': '2e614be960ee1d', + 'impid': '2e614be960ee1d', + 'price': 7.91, + 'mediatype': 'banner', + 'adid': '24277955', + 'adm': 'creativity_banner', + 'adomain': [ + 'aidem.com' + ], + 'iurl': 'http://www.aidem.com', + 'cat': [], + 'cid': '4193561', + 'crid': '24277955', + 'w': 300, + 'h': 250, + 'ext': { + 'dspid': 85, + 'advbrandid': 1246, + 'advbrand': 'AIDEM' + } + }, + ], + seat: '6047231' + } + ], + cur: 'USD' + }, +} + +const SERVER_RESPONSE_VIDEO = { + body: { + id: 'efa1930a-bc3e-4fd0-8368-08bc40236b4f', + seatbid: [ + { + bid: [ + // VIDEO + { + 'id': '2876a29392a47c', + 'impid': '2876a29392a47c', + 'price': 7.93, + 'mediatype': 'video', + 'adid': '24277955', + 'adm': 'https://hermes.aidemsrv.com/vast-tag/cl9mzhhd502uq09l720uegb02?auction_id={{AUCTION_ID}}&cachebuster={{CACHEBUSTER}}', + 'adomain': [ + 'aidem.com' + ], + 'iurl': 'http://www.aidem.com', + 'cat': [], + 'cid': '4193561', + 'crid': '24277955', + 'w': 640, + 'h': 480, + 'ext': { + 'dspid': 85, + 'advbrandid': 1246, + 'advbrand': 'AIDEM' + } + } + ], + seat: '6047231' + } + ], + cur: 'USD' + }, +} + +const WIN_NOTICE = { + 'adId': '3a20ee5dc78c1e', + 'adUnitCode': 'div-gpt-ad-1460505748561-0', + 'creativeId': '24277955', + 'cpm': 1, + 'netRevenue': false, + 'adserverTargeting': { + 'hb_bidder': 'aidem', + 'hb_adid': '3a20ee5dc78c1e', + 'hb_pb': '1.00', + 'hb_size': '300x250', + 'hb_source': 'client', + 'hb_format': 'banner', + 'hb_adomain': 'tenutabene.it' + }, + 'auctionId': '85864730-6cbc-4e56-bc3c-a4a6596dca5b', + 'currency': [ + 'USD' + ], + 'mediaType': 'banner', + 'size': '300x250', + 'width': 300, + 'height': 250, + 'status': 'rendered', + 'transactionId': 'ce089116-4251-45c3-bdbb-3a03cb13816b', + 'ttl': 300, + 'requestTimestamp': 1666796241007, + 'responseTimestamp': 1666796241021, + metrics: { + getMetrics() { + return { + + } + } + } +} + +const TIMEOUT_NOTICE = [ + { + 'adUnitCode': 'div-gpt-ad-1460505748561-0', + 'auctionId': 'b57faab7-23f7-4b63-90db-67b259d20db7', + 'bidId': '233f0aa47ccb68', + 'bidderRequestId': '1c53857d1ce616', + 'transactionId': '5c09d600-6da1-4a66-8e97-a67ace3083a4', + metrics: { + getMetrics() { + return { + + } + } + } + } +] + +const ERROR_NOTICE = { + 'message': 'Prebid.js: Server call for aidem failed.', + 'url': 'http%3A%2F%2Flocalhost%3A9999%2FintegrationExamples%2Fgpt%2Fhello_world.html%3Fpbjs_debug%3Dtrue', + 'auctionId': 'b57faab7-23f7-4b63-90db-67b259d20db7', + 'bidderRequestId': '1c53857d1ce616', + 'timeout': 1000, + 'bidderCode': 'aidem', + metrics: { + getMetrics() { + return { + + } + } + } +} + +describe('Aidem adapter', () => { + describe('isBidRequestValid', () => { + it('should return true for each valid bid requests', function () { + // spec.isBidRequestValid() + VALID_BIDS.forEach((value, index) => { + expect(spec.isBidRequestValid(value)).to.be.true + }) + }); + + it('should return false for each invalid bid requests', function () { + // spec.isBidRequestValid() + INVALID_BIDS.forEach((value, index) => { + expect(spec.isBidRequestValid(value)).to.be.false + }) + }); + + it('should return true if valid banner sizes are specified in params as single array', function () { + // spec.isBidRequestValid() + const validBannerRequest = utils.deepClone(VALID_BIDS[0]) + deepSetValue(validBannerRequest.params, 'banner.size', [300, 250]) + expect(spec.isBidRequestValid(validBannerRequest)).to.be.true + }); + + it('should return true if valid banner sizes are specified in params as array of array', function () { + // spec.isBidRequestValid() + const validBannerRequest = utils.deepClone(VALID_BIDS[0]) + deepSetValue(validBannerRequest.params, 'banner.size', [[300, 600]]) + expect(spec.isBidRequestValid(validBannerRequest)).to.be.true + }); + + it('should return true if valid video sizes are specified in params as single array', function () { + // spec.isBidRequestValid() + const validVideoRequest = utils.deepClone(VALID_BIDS[1]) + deepSetValue(validVideoRequest.params, 'video.size', [640, 480]) + expect(spec.isBidRequestValid(validVideoRequest)).to.be.true + }); + + it('should return false if params size is not an array', function () { + // spec.isBidRequestValid() + const validVideoRequest = utils.deepClone(VALID_BIDS[1]) + deepSetValue(validVideoRequest.params, 'video.size', [[300], [[300, 600]]]) + expect(spec.isBidRequestValid(validVideoRequest)).to.be.false + }); + }); + + describe('buildRequests', () => { + it('should match server requirements', () => { + const requests = spec.buildRequests(DEFAULT_VALID_BANNER_REQUESTS, VALID_BIDDER_REQUEST); + expect(requests).to.be.an('object'); + expect(requests.method).to.be.a('string') + expect(requests.data).to.be.a('string') + expect(requests.options).to.be.an('object').that.have.a.property('withCredentials') + }); + + it('should have a well formatted banner payload', () => { + const requests = spec.buildRequests(DEFAULT_VALID_BANNER_REQUESTS, VALID_BIDDER_REQUEST); + const payload = JSON.parse(requests.data) + expect(payload).to.be.a('object').that.has.all.keys( + 'id', 'imp', 'mediaTypes', 'device', 'cur', 'tz', 'regs', 'site', 'environment', 'at', 'user' + ) + expect(payload.imp).to.be.a('array').that.has.lengthOf(DEFAULT_VALID_BANNER_REQUESTS.length) + + expect(payload.imp[0]).to.be.a('object').that.has.all.keys( + 'banner', 'id', 'mediatype', 'imp_ext', 'tid', 'siteId' + ) + expect(payload.imp[0].banner).to.be.a('object').that.has.all.keys( + 'format', 'topframe' + ) + }); + + it('should have a well formatted video payload', () => { + const requests = spec.buildRequests(DEFAULT_VALID_VIDEO_REQUESTS, VALID_BIDDER_REQUEST); + const payload = JSON.parse(requests.data) + expect(payload).to.be.a('object').that.has.all.keys( + 'id', 'imp', 'mediaTypes', 'device', 'cur', 'tz', 'regs', 'site', 'environment', 'at', 'user' + ) + expect(payload.imp).to.be.a('array').that.has.lengthOf(DEFAULT_VALID_VIDEO_REQUESTS.length) + + expect(payload.imp[0]).to.be.a('object').that.has.all.keys( + 'video', 'id', 'mediatype', 'imp_ext', 'tid', 'siteId' + ) + expect(payload.imp[0].video).to.be.a('object').that.has.all.keys( + 'format', 'mimes', 'minDuration', 'maxDuration', 'protocols' + ) + }); + + it('should have a well formatted bid floor payload if configured', () => { + const validBannerRequests = utils.deepClone(DEFAULT_VALID_BANNER_REQUESTS) + validBannerRequests[0].params.floor = { + value: 1.98, + currency: 'USD' + } + const requests = spec.buildRequests(validBannerRequests, VALID_BIDDER_REQUEST); + const payload = JSON.parse(requests.data) + const { floor } = payload.imp[0] + expect(floor).to.be.a('object').that.has.all.keys( + 'value', 'currency' + ) + }); + }) + + describe('interpretResponse', () => { + it('should return a valid bid array with a banner bid', () => { + const response = utils.deepClone(SERVER_RESPONSE_BANNER) + const interpreted = spec.interpretResponse(response) + expect(interpreted).to.be.a('array').that.has.lengthOf(1) + interpreted.forEach(value => { + expect(value).to.be.a('object').that.has.all.keys( + 'ad', 'cpm', 'creativeId', 'currency', 'height', 'mediaType', 'meta', 'netRevenue', 'requestId', 'ttl', 'width', 'dealId' + ) + }) + }); + + it('should return a valid bid array with a banner bid', () => { + const response = utils.deepClone(SERVER_RESPONSE_VIDEO) + const interpreted = spec.interpretResponse(response) + expect(interpreted).to.be.a('array').that.has.lengthOf(1) + interpreted.forEach(value => { + expect(value).to.be.a('object').that.has.all.keys( + 'vastUrl', 'cpm', 'creativeId', 'currency', 'height', 'mediaType', 'meta', 'netRevenue', 'requestId', 'ttl', 'width', 'dealId' + ) + }) + }); + + it('should return a valid bid array with netRevenue', () => { + const response = utils.deepClone(SERVER_RESPONSE_BANNER) + response.body.seatbid[0].bid[0].isNet = true + const interpreted = spec.interpretResponse(response) + expect(interpreted).to.be.a('array').that.has.lengthOf(1) + expect(interpreted[0].netRevenue).to.be.true + }); + + it('should return an empty bid array if one of seatbid entry is missing price property', () => { + const response = utils.deepClone(SERVER_RESPONSE_BANNER) + delete response.body.seatbid[0].bid[0].price + const interpreted = spec.interpretResponse(response) + expect(interpreted).to.be.a('array').that.has.lengthOf(0) + }); + + it('should return an empty bid array if one of seatbid entry is missing adm property', () => { + const response = utils.deepClone(SERVER_RESPONSE_BANNER) + delete response.body.seatbid[0].bid[0].adm + const interpreted = spec.interpretResponse(response) + expect(interpreted).to.be.a('array').that.has.lengthOf(0) + }); + }) + + // TODO verify that outgoing payload match expected structure + describe('onBidWon', () => { + it(`should exists and type function`, function () { + expect(spec.onBidWon).to.exist.and.to.be.a('function') + }); + + it(`should send a valid bid won notice`, function () { + // TODO check parameter after zero is working + spec.onBidWon(WIN_NOTICE); + // server.respondWith('POST', WIN_EVENT_URL, [ + // 400, {'Content-Type': 'application/json'}, ) + // ]); + expect(server.requests.length).to.equal(1); + }); + }); + + describe('onTimeout', () => { + it(`should exists and type function`, function () { + expect(spec.onTimeout).to.exist.and.to.be.a('function') + }); + + it(`should send a valid timeout notice`, function () { + spec.onTimeout(TIMEOUT_NOTICE); + expect(server.requests.length).to.equal(1); + const { bids } = JSON.parse(server.requests[0].requestBody) + expect(bids).to.be.a('array').that.has.lengthOf(1) + _each(bids, (bid) => { + expect(bid).to.be.a('object').that.has.all.keys('adUnitCode', 'auctionId', 'bidId', 'bidderRequestId', 'transactionId', 'metrics') + }) + }); + }); + + describe('onBidderError', () => { + it(`should exists and type function`, function () { + expect(spec.onBidderError).to.exist.and.to.be.a('function') + }); + + it(`should send a valid error notice`, function () { + spec.onBidderError({ bidderRequest: ERROR_NOTICE }) + expect(server.requests.length).to.equal(1); + const body = JSON.parse(server.requests[0].requestBody) + expect(body).to.be.a('object').that.has.all.keys('message', 'auctionId', 'bidderRequestId', 'url', 'metrics') + // const { bids } = JSON.parse(server.requests[0].requestBody) + // expect(bids).to.be.a('array').that.has.lengthOf(1) + // _each(bids, (bid) => { + // expect(bid).to.be.a('object').that.has.all.keys('adUnitCode', 'auctionId', 'bidId', 'bidderRequestId', 'transactionId', 'metrics') + // }) + }); + }); + + describe('setEndPoints', () => { + it(`should exists and type function`, function () { + expect(setEndPoints).to.exist.and.to.be.a('function') + }); + + it(`should not modify default endpoints`, function () { + const endpoints = setEndPoints() + const requestURL = new URL(endpoints.request) + const winNoticeURL = new URL(endpoints.notice.win) + const timeoutNoticeURL = new URL(endpoints.notice.timeout) + const errorNoticeURL = new URL(endpoints.notice.error) + + expect(requestURL.host).to.equal('zero.aidemsrv.com') + expect(winNoticeURL.host).to.equal('zero.aidemsrv.com') + expect(timeoutNoticeURL.host).to.equal('zero.aidemsrv.com') + expect(errorNoticeURL.host).to.equal('zero.aidemsrv.com') + + expect(decodeURIComponent(requestURL.pathname)).to.equal('/bid/request') + expect(decodeURIComponent(winNoticeURL.pathname)).to.equal('/notice/win') + expect(decodeURIComponent(timeoutNoticeURL.pathname)).to.equal('/notice/timeout') + expect(decodeURIComponent(errorNoticeURL.pathname)).to.equal('/notice/error') + }); + + it(`should not change request endpoint`, function () { + const endpoints = setEndPoints('default') + const requestURL = new URL(endpoints.request) + expect(decodeURIComponent(requestURL.pathname)).to.equal('/bid/request') + }); + + it(`should change to local env`, function () { + const endpoints = setEndPoints('local') + const requestURL = new URL(endpoints.request) + const winNoticeURL = new URL(endpoints.notice.win) + const timeoutNoticeURL = new URL(endpoints.notice.timeout) + const errorNoticeURL = new URL(endpoints.notice.error) + + expect(requestURL.host).to.equal('127.0.0.1:8787') + expect(winNoticeURL.host).to.equal('127.0.0.1:8787') + expect(timeoutNoticeURL.host).to.equal('127.0.0.1:8787') + expect(errorNoticeURL.host).to.equal('127.0.0.1:8787') + }); + + it(`should add a path prefix`, function () { + const endpoints = setEndPoints('local', '/path') + const requestURL = new URL(endpoints.request) + const winNoticeURL = new URL(endpoints.notice.win) + const timeoutNoticeURL = new URL(endpoints.notice.timeout) + const errorNoticeURL = new URL(endpoints.notice.error) + + expect(decodeURIComponent(requestURL.pathname)).to.equal('/path/bid/request') + expect(decodeURIComponent(winNoticeURL.pathname)).to.equal('/path/notice/win') + expect(decodeURIComponent(timeoutNoticeURL.pathname)).to.equal('/path/notice/timeout') + expect(decodeURIComponent(errorNoticeURL.pathname)).to.equal('/path/notice/error') + }); + + it(`should add a path prefix and change request endpoint`, function () { + const endpoints = setEndPoints('local', '/path') + const requestURL = new URL(endpoints.request) + const winNoticeURL = new URL(endpoints.notice.win) + const timeoutNoticeURL = new URL(endpoints.notice.timeout) + const errorNoticeURL = new URL(endpoints.notice.error) + + expect(decodeURIComponent(requestURL.pathname)).to.equal('/path/bid/request') + expect(decodeURIComponent(winNoticeURL.pathname)).to.equal('/path/notice/win') + expect(decodeURIComponent(timeoutNoticeURL.pathname)).to.equal('/path/notice/timeout') + expect(decodeURIComponent(errorNoticeURL.pathname)).to.equal('/path/notice/error') + }); + }); + + describe('config', () => { + beforeEach(() => { + config.setConfig({ + aidem: { + env: 'main' + } + }); + }) + + it(`should not override default endpoints`, function () { + config.setConfig({ + aidem: { + env: 'unknown', + path: '/test' + } + }); + const { url } = spec.buildRequests(DEFAULT_VALID_BANNER_REQUESTS, VALID_BIDDER_REQUEST); + const requestURL = new URL(url) + expect(requestURL.host).to.equal('zero.aidemsrv.com') + }); + + it(`should set local endpoints`, function () { + config.setConfig({ + aidem: { + env: 'local', + path: '/test' + } + }); + const { url } = spec.buildRequests(DEFAULT_VALID_BANNER_REQUESTS, VALID_BIDDER_REQUEST); + const requestURL = new URL(url) + expect(requestURL.host).to.equal('127.0.0.1:8787') + }); + + it(`should set correct connection default`, function () { + const { data } = spec.buildRequests(DEFAULT_VALID_BANNER_REQUESTS, VALID_BIDDER_REQUEST); + const request = JSON.parse(data) + expect(request.device.connectiontype).to.equal(0) + }); + + it(`should set correct connection type ethernet`, function () { + navigator.connection.type = 'ethernet' + const { data } = spec.buildRequests(DEFAULT_VALID_BANNER_REQUESTS, VALID_BIDDER_REQUEST); + const request = JSON.parse(data) + expect(request.device.connectiontype).to.equal(1) + }); + + it(`should set correct connection type wifi`, function () { + navigator.connection.type = 'wifi' + const { data } = spec.buildRequests(DEFAULT_VALID_BANNER_REQUESTS, VALID_BIDDER_REQUEST); + const request = JSON.parse(data) + expect(request.device.connectiontype).to.equal(2) + }); + + it(`should populate prebidRequest site object`, function () { + config.setConfig({ + ortb2: { + site: { + name: 'example', + domain: 'page.example.com', + cat: ['IAB2'], + sectioncat: ['IAB2-2'], + pagecat: ['IAB2-2'], + keywords: 'power tools, drills', + ext: { + data: { // fields that aren't part of openrtb 2.5 + pageType: 'article', + category: 'repair' + } + } + }, + } + }); + const { data } = spec.buildRequests(DEFAULT_VALID_BANNER_REQUESTS, VALID_BIDDER_REQUEST); + const payload = JSON.parse(data) + // expect(payload.imp).to.be.a('array').that.has.lengthOf(1) + expect(payload.site).to.be.exist + const { site } = payload + expect(site).to.be.a('object').that.has.all.keys('cat', 'domain', 'page', 'referer', 'sectioncat', 'keywords', 'site_ext') + expect(site.cat).to.be.eql(['IAB2']) + expect(site.sectioncat).to.be.eql(['IAB2-2']) + expect(site.keywords).to.be.eql('power tools, drills') + }); + + it(`should set coppa`, function () { + config.setConfig({ + coppa: true + }); + const { data } = spec.buildRequests(DEFAULT_VALID_BANNER_REQUESTS, VALID_BIDDER_REQUEST); + const request = JSON.parse(data) + expect(request.regs.coppa).to.equal(true) + }); + + it(`should set gdpr to true`, function () { + config.setConfig({ + consentManagement: { + gdpr: { + // any data here set gdpr to true + }, + } + }); + const { data } = spec.buildRequests(DEFAULT_VALID_BANNER_REQUESTS, VALID_BIDDER_REQUEST); + const request = JSON.parse(data) + expect(request.regs.gdpr).to.equal(true) + }); + + it(`should set usp_consent string`, function () { + config.setConfig({ + consentManagement: { + usp: { + cmpApi: 'static', + consentData: { + getUSPData: { + uspString: '1YYY' + } + } + } + } + }); + const { data } = spec.buildRequests(DEFAULT_VALID_BANNER_REQUESTS, VALID_BIDDER_REQUEST); + const request = JSON.parse(data) + expect(request.regs.us_privacy).to.equal('1YYY') + }); + + it(`should not set usp_consent string`, function () { + config.setConfig({ + consentManagement: { + usp: { + cmpApi: 'iab', + consentData: { + getUSPData: { + uspString: '1YYY' + } + } + } + } + }); + const { data } = spec.buildRequests(DEFAULT_VALID_BANNER_REQUESTS, VALID_BIDDER_REQUEST); + const request = JSON.parse(data) + expect(request.regs.us_privacy).to.undefined + }); + }); +}); From 61c803eeb8dcca74d5e63c48b1f0cd9a5149f2d5 Mon Sep 17 00:00:00 2001 From: Giovanni Sollazzo Date: Fri, 11 Nov 2022 20:05:45 +0100 Subject: [PATCH 03/21] update --- modules/aidemBidAdapter.js | 298 +++++----------------- test/spec/modules/aidemBidAdapter_spec.js | 185 ++++---------- 2 files changed, 110 insertions(+), 373 deletions(-) diff --git a/modules/aidemBidAdapter.js b/modules/aidemBidAdapter.js index e817d70b980..91e64a6a807 100644 --- a/modules/aidemBidAdapter.js +++ b/modules/aidemBidAdapter.js @@ -1,15 +1,4 @@ -import { - _each, - contains, - deepAccess, - deepSetValue, - getDNT, - isInteger, - logError, - logInfo, - isBoolean, - isStr -} from '../src/utils.js'; +import {_each, contains, deepAccess, deepSetValue, getDNT, isBoolean, isStr, logError, logInfo} from '../src/utils.js'; import {config} from '../src/config.js'; import {BANNER, VIDEO} from '../src/mediaTypes.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; @@ -60,23 +49,17 @@ export function setEndPoints(env = null, path = '', mediaType = BANNER) { return endpoints } -let ortb2 = {} - config.getConfig('aidem', function (config) { if (config.aidem.env) { setEndPoints(config.aidem.env, config.aidem.path, config.aidem.mediaType) } }) -config.getConfig('ortb2', function (config) { - ortb2 = Object.assign({}, ortb2, config.ortb2) -}) - // AIDEM Custom FN function recur(obj) { var result = {}; var _tmp; for (var i in obj) { // enabledPlugin is too nested, also skip functions if (!(i === 'enabledPlugin' || typeof obj[i] === 'function')) { - if (typeof obj[i] === 'object') { + if (typeof obj[i] === 'object' && obj[i] !== null) { // get props recursively _tmp = recur(obj[i]); // if object is not {} @@ -92,37 +75,6 @@ function recur(obj) { return result; } -/** - * Determines whether or not the given object is valid size format. - * - * @param {*} size The object to be validated. - * @return {boolean} True if this is a valid size format, and false otherwise. - */ -function isValidSize(size) { - return Array.isArray(size) && size.length === 2 && isInteger(size[0]) && isInteger(size[1]); -} - -/** - * Determines whether or not the given size object is an element of the size - * array. - * - * @param {array} sizeArray The size array. - * @param {object} size The size object. - * @return {boolean} True if the size object is an element of the size array, and false - * otherwise. - */ -function includesSize(sizeArray = [], size = []) { - if (isValidSize(sizeArray)) { - return sizeArray[0] === size[0] && sizeArray[1] === size[1]; - } - for (let i = 0; i < sizeArray.length; i++) { - if (sizeArray[i][0] === size[0] && sizeArray[i][1] === size[1]) { - return true; - } - } - return false; -} - // ================================================================================= function getConnectionType() { const connection = navigator.connection || navigator.webkitConnection; @@ -158,7 +110,7 @@ function getDevice() { const language = navigator.language || navigator.browserLanguage || navigator.userLanguage || navigator.systemLanguage; return { ua: navigator.userAgent, - dnt: getDNT() ? 1 : 0, + dnt: !!getDNT(), language: language, connectiontype: getConnectionType(), screen_width: screen.width, @@ -171,68 +123,43 @@ function getRegs() { const consentManagement = config.getConfig('consentManagement') const coppa = config.getConfig('coppa') if (consentManagement && !!(consentManagement.gdpr)) { - deepSetValue(regs, 'gdpr', !!consentManagement.gdpr); + deepSetValue(regs, 'gdpr_applies', !!consentManagement.gdpr); + } else { + deepSetValue(regs, 'gdpr_applies', false); } if (consentManagement && deepAccess(consentManagement, 'usp.cmpApi') === 'static') { + deepSetValue(regs, 'usp_applies', !!deepAccess(consentManagement, 'usp')); deepSetValue(regs, 'us_privacy', deepAccess(consentManagement, 'usp.consentData.getUSPData.uspString')); + } else { + deepSetValue(regs, 'usp_applies', false); } + if (isBoolean(coppa)) { - deepSetValue(regs, 'coppa', !!coppa); + deepSetValue(regs, 'coppa_applies', !!coppa); + } else { + deepSetValue(regs, 'coppa_applies', false); } return regs; } -/** - * Returns bidder request page url. - * - * @param {Object} bidderRequest - * @return {string} - */ function getPageUrl(bidderRequest) { return bidderRequest?.refererInfo?.page } -function buildWonBidNotice(bid) { - const winNotice = { - adId: bid.adId, - adUnitCode: bid.adUnitCode, - creativeId: bid.creativeId, +function buildWinNotice(bid) { + return { + burl: deepAccess(bid, 'meta.burl'), cpm: bid.cpm, - netRevenue: bid.netRevenue, - adserverTargeting: bid.adserverTargeting, - auctionId: bid.auctionId, currency: bid.currency, - mediaType: bid.mediaType, - size: bid.size, - width: bid.width, - height: bid.height, - status: bid.status, + impid: deepAccess(bid, 'meta.impid'), + adUnitCode: bid.adUnitCode, + auctionId: bid.auctionId, transactionId: bid.transactionId, ttl: bid.ttl, requestTimestamp: bid.requestTimestamp, responseTimestamp: bid.responseTimestamp, - metrics: {} - } - - if (bid.metrics && typeof bid.metrics.getMetrics === 'function') { - const metrics = bid.metrics.getMetrics() - deepSetValue(winNotice.metrics, 'requestBids.validate', metrics['requestBids.validate']) - deepSetValue(winNotice.metrics, 'requestBids.makeRequests', metrics['requestBids.makeRequests']) - deepSetValue(winNotice.metrics, 'requestBids.total', metrics['requestBids.total']) - deepSetValue(winNotice.metrics, 'requestBids.callBids', metrics['requestBids.callBids']) - deepSetValue(winNotice.metrics, 'adapter.client.validate', metrics['adapter.client.validate']) - deepSetValue(winNotice.metrics, 'adapter.client.buildRequests', metrics['adapter.client.buildRequests']) - deepSetValue(winNotice.metrics, 'adapter.client.total', metrics['adapter.client.total']) - deepSetValue(winNotice.metrics, 'adapter.client.net', metrics['adapter.client.net']) - deepSetValue(winNotice.metrics, 'adapter.client.interpretResponse', metrics['adapter.client.interpretResponse']) - deepSetValue(winNotice.metrics, 'addBidResponse.validate', metrics['addBidResponse.validate']) - deepSetValue(winNotice.metrics, 'addBidResponse.total', metrics['addBidResponse.total']) - deepSetValue(winNotice.metrics, 'render.pending', metrics['render.pending']) - deepSetValue(winNotice.metrics, 'render.e2e', metrics['render.e2e']) } - - return winNotice } // Called for every bid that has timed out @@ -247,24 +174,8 @@ function buildTimeoutNotice(prebidTimeoutBids) { bidId: bid.bidId, bidderRequestId: bid.bidderRequestId, transactionId: bid.transactionId, - mediaTypes: bid.mediaTypes, - metrics: { }, - timeout: bid.timeout, + mediaTypes: bid.mediaTypes } - - if (bid.metrics && typeof bid.metrics.getMetrics === 'function') { - const metrics = bid.metrics.getMetrics() - deepSetValue(notice.metrics, 'requestBids.validate', metrics['requestBids.validate']) - deepSetValue(notice.metrics, 'requestBids.makeRequests', metrics['requestBids.makeRequests']) - deepSetValue(notice.metrics, 'requestBids.total', metrics['requestBids.total']) - deepSetValue(notice.metrics, 'requestBids.callBids', metrics['requestBids.callBids']) - deepSetValue(notice.metrics, 'adapter.client.validate', metrics['adapter.client.validate']) - deepSetValue(notice.metrics, 'adapter.client.buildRequests', metrics['adapter.client.buildRequests']) - deepSetValue(notice.metrics, 'adapter.client.total', metrics['adapter.client.total']) - deepSetValue(notice.metrics, 'adapter.client.net', metrics['adapter.client.net']) - deepSetValue(notice.metrics, 'adapter.client.interpretResponse', metrics['adapter.client.interpretResponse']) - } - timeoutNotice.bids.push(notice) }) @@ -272,42 +183,13 @@ function buildTimeoutNotice(prebidTimeoutBids) { } function buildErrorNotice(prebidErrorResponse) { - const errorNotice = { + return { message: `Prebid.js: Server call for ${prebidErrorResponse.bidderCode} failed.`, url: encodeURIComponent(getPageUrl(prebidErrorResponse)), auctionId: prebidErrorResponse.auctionId, bidderRequestId: prebidErrorResponse.bidderRequestId, metrics: {} } - if (prebidErrorResponse.metrics && typeof prebidErrorResponse.metrics.getMetrics === 'function') { - const metrics = prebidErrorResponse.metrics.getMetrics() - deepSetValue(errorNotice.metrics, 'requestBids.validate', metrics['requestBids.validate']) - deepSetValue(errorNotice.metrics, 'requestBids.makeRequests', metrics['requestBids.makeRequests']) - deepSetValue(errorNotice.metrics, 'requestBids.total', metrics['requestBids.total']) - deepSetValue(errorNotice.metrics, 'requestBids.callBids', metrics['requestBids.callBids']) - deepSetValue(errorNotice.metrics, 'adapter.client.validate', metrics['adapter.client.validate']) - deepSetValue(errorNotice.metrics, 'adapter.client.buildRequests', metrics['adapter.client.buildRequests']) - deepSetValue(errorNotice.metrics, 'adapter.client.total', metrics['adapter.client.total']) - deepSetValue(errorNotice.metrics, 'adapter.client.net', metrics['adapter.client.net']) - deepSetValue(errorNotice.metrics, 'adapter.client.interpretResponse', metrics['adapter.client.interpretResponse']) - } - return errorNotice -} - -/** - * Get One size from Size Array - * [[250,350]] -> [250, 350] - * [250, 350] -> [250, 350] - * @param {array} sizes array of sizes - */ -function getFirstSize(sizes = []) { - if (isValidSize(sizes)) { - return sizes; - } else if (isValidSize(sizes[0])) { - return sizes[0]; - } - - return false; } function hasValidFloor(obj) { @@ -344,27 +226,21 @@ function getPrebidRequestFields(bidderRequest, bidRequests) { setPrebidRequestEnvironment(payload) // AT auction type deepSetValue(payload, 'at', 1); - // User - payload.user = {}; return payload } function setPrebidImpressionObject(bidRequests, payload) { payload.imp = []; - payload.mediaTypes = [] _each(bidRequests, function (bidRequest) { const impressionObject = {}; // Placement or ad tag used to initiate the auction deepSetValue(impressionObject, 'id', bidRequest.bidId); - // Site id - deepSetValue(impressionObject, 'siteId', deepAccess(bidRequest, 'params.siteId')); - // Tag id + // Transaction id deepSetValue(impressionObject, 'tid', deepAccess(bidRequest, 'transactionId')); + // Site id + deepSetValue(payload, 'site.id', deepAccess(bidRequest, 'params.siteId')); const mediaType = getMediaType(bidRequest) - if (!payload.mediaTypes.includes(mediaType)) { - payload.mediaTypes.push(mediaType) - } switch (mediaType) { case 'banner': setPrebidImpressionObjectBanner(bidRequest, impressionObject) @@ -387,10 +263,10 @@ function setPrebidSiteObject(bidderRequest, payload) { deepSetValue(payload, 'site.domain', deepAccess(bidderRequest, 'refererInfo.domain')); deepSetValue(payload, 'site.page', deepAccess(bidderRequest, 'refererInfo.page')); deepSetValue(payload, 'site.referer', deepAccess(bidderRequest, 'refererInfo.ref')); - deepSetValue(payload, 'site.cat', deepAccess(ortb2, 'site.cat')); - deepSetValue(payload, 'site.sectioncat', deepAccess(ortb2, 'site.sectioncat')); - deepSetValue(payload, 'site.keywords', deepAccess(ortb2, 'site.keywords')); - deepSetValue(payload, 'site.site_ext', deepAccess(ortb2, 'site.ext')); // see https://docs.prebid.org/features/firstPartyData.html + deepSetValue(payload, 'site.cat', deepAccess(bidderRequest, 'ortb2.site.cat')); + deepSetValue(payload, 'site.sectioncat', deepAccess(bidderRequest, 'ortb2.site.sectioncat')); + deepSetValue(payload, 'site.keywords', deepAccess(bidderRequest, 'ortb2.site.keywords')); + deepSetValue(payload, 'site.site_ext', deepAccess(bidderRequest, 'ortb2.site.ext')); // see https://docs.prebid.org/features/firstPartyData.html } function setPrebidRequestEnvironment(payload) { @@ -452,15 +328,15 @@ function setPrebidImpressionObjectVideo(bidRequest, impressionObject) { function getPrebidResponseBidObject(openRTBResponseBidObject) { const prebidResponseBidObject = {}; // Common properties - deepSetValue(prebidResponseBidObject, 'requestId', openRTBResponseBidObject.id); + deepSetValue(prebidResponseBidObject, 'requestId', openRTBResponseBidObject.impid); deepSetValue(prebidResponseBidObject, 'cpm', parseFloat(openRTBResponseBidObject.price)); - deepSetValue(prebidResponseBidObject, 'currency', openRTBResponseBidObject.currency ? openRTBResponseBidObject.currency.toUpperCase() : DEFAULT_CURRENCY); + deepSetValue(prebidResponseBidObject, 'creativeId', openRTBResponseBidObject.crid); + deepSetValue(prebidResponseBidObject, 'currency', openRTBResponseBidObject.cur ? openRTBResponseBidObject.cur.toUpperCase() : DEFAULT_CURRENCY); deepSetValue(prebidResponseBidObject, 'width', openRTBResponseBidObject.w); deepSetValue(prebidResponseBidObject, 'height', openRTBResponseBidObject.h); - deepSetValue(prebidResponseBidObject, 'creativeId', openRTBResponseBidObject.adid); - deepSetValue(prebidResponseBidObject, 'dealId', openRTBResponseBidObject.deal) - deepSetValue(prebidResponseBidObject, 'netRevenue', openRTBResponseBidObject.isNet ? openRTBResponseBidObject.isNet : false); - deepSetValue(prebidResponseBidObject, 'ttl', 300); + deepSetValue(prebidResponseBidObject, 'dealId', openRTBResponseBidObject.dealid) + deepSetValue(prebidResponseBidObject, 'netRevenue', true); + deepSetValue(prebidResponseBidObject, 'ttl', 60000); if (openRTBResponseBidObject.mediatype === VIDEO) { logInfo('bidObject.mediatype == VIDEO'); @@ -476,7 +352,18 @@ function getPrebidResponseBidObject(openRTBResponseBidObject) { } function setPrebidResponseBidObjectMeta(prebidResponseBidObject, openRTBResponseBidObject) { - deepSetValue(prebidResponseBidObject, 'meta.advertiserDomains', openRTBResponseBidObject.adomain && Array.isArray(openRTBResponseBidObject.adomain) ? openRTBResponseBidObject.adomain : []); + deepSetValue(prebidResponseBidObject, 'meta.advertiserDomains', openRTBResponseBidObject.adomain); + if (openRTBResponseBidObject.cat && Array.isArray(openRTBResponseBidObject.cat)) { + const primaryCatId = openRTBResponseBidObject.cat.shift(); + deepSetValue(prebidResponseBidObject, 'meta.primaryCatId', primaryCatId); + deepSetValue(prebidResponseBidObject, 'meta.secondaryCatIds', openRTBResponseBidObject.cat); + } + deepSetValue(prebidResponseBidObject, 'meta.id', openRTBResponseBidObject.id); + deepSetValue(prebidResponseBidObject, 'meta.adid', openRTBResponseBidObject.adid); + deepSetValue(prebidResponseBidObject, 'meta.burl', openRTBResponseBidObject.burl); + deepSetValue(prebidResponseBidObject, 'meta.impid', openRTBResponseBidObject.impid); + deepSetValue(prebidResponseBidObject, 'meta.cat', openRTBResponseBidObject.cat); + deepSetValue(prebidResponseBidObject, 'meta.cid', openRTBResponseBidObject.cid); } function hasValidMediaType(bidRequest) { @@ -513,39 +400,6 @@ function hasValidVideoMediaType(bidRequest) { return true } -function hasValidBannerBidderParameters(bidRequest) { - const mediaTypesSizes = deepAccess(bidRequest, 'mediaTypes.banner.sizes'); - const size = deepAccess(bidRequest, 'params.banner.size'); - const flatten = getFirstSize(size); - if (size && !flatten) { - logError('AIDEM Bid Adapter: size has invalid format.', { bidder: BIDDER_CODE, code: ERROR_CODES.BID_SIZE_INVALID_FORMAT }); - return false; - } - - if (size && !(includesSize(mediaTypesSizes, flatten))) { - logError('AIDEM Bid Adapter: bidder banner size is not included in ad unit banner sizes.', { bidder: BIDDER_CODE, code: ERROR_CODES.BID_SIZE_NOT_INCLUDED }); - return false; - } - - return true -} - -function hasValidVideoBidderParameters(bidRequest) { - const mediaTypesSizes = deepAccess(bidRequest, 'mediaTypes.video.playerSize'); - const size = deepAccess(bidRequest, 'params.video.size'); - const flatten = getFirstSize(size); - if (size && !flatten) { - logError('AIDEM Bid Adapter: size has invalid format.', { bidder: BIDDER_CODE, code: ERROR_CODES.BID_SIZE_INVALID_FORMAT }); - return false; - } - if (size && !(includesSize(mediaTypesSizes, size))) { - logError('AIDEM Bid Adapter: bidder banner size is not included in ad unit playerSize.', { bidder: BIDDER_CODE, code: ERROR_CODES.BID_SIZE_NOT_INCLUDED }); - return false; - } - - return hasValidVideoParameters(bidRequest); -} - function hasValidVideoParameters(bidRequest) { let valid = true const adUnitsParameters = deepAccess(bidRequest, 'mediaTypes.video'); @@ -576,12 +430,6 @@ function hasValidParameters(bidRequest) { export const spec = { code: BIDDER_CODE, supportedMediaTypes: SUPPORTED_MEDIA_TYPES, - /** - * Determines whether or not the given bid request is valid. - * - * @param {BidRequest} bidRequest The bid params to validate. - * @return boolean True if this is a valid bid, and false otherwise. - */ isBidRequestValid: function(bidRequest) { logInfo('bid: ', bidRequest); @@ -592,28 +440,18 @@ export const spec = { if (hasBannerMediaType(bidRequest) && !hasValidBannerMediaType(bidRequest)) { return false } + if (hasVideoMediaType(bidRequest) && !hasValidVideoMediaType(bidRequest)) { return false } - // check if request has valid media type parameters at adUnit level - if (hasBannerMediaType(bidRequest) && !hasValidBannerBidderParameters(bidRequest)) { - return false - } - if (hasVideoMediaType(bidRequest) && !hasValidVideoBidderParameters(bidRequest)) { + if (hasVideoMediaType(bidRequest) && !hasValidVideoParameters(bidRequest)) { return false } return hasValidParameters(bidRequest) }, - /** - * Make a server request from the list of BidRequests. - * - * @param validBidRequests[] - An array of bidRequest objects, one for each AdUnit that your module is involved in - * @param bidderRequest - The master bidRequest object. This object is useful because it carries a couple of bid parameters that are global to all the bids - * @return ServerRequest Info describing the request to the server. - */ buildRequests: function(validBidRequests, bidderRequest) { logInfo('validBidRequests: ', validBidRequests); logInfo('bidderRequest: ', bidderRequest); @@ -630,47 +468,28 @@ export const spec = { }; }, - /** - * Unpack the response from the server into a list of bids. - * - * @param {ServerResponse} serverResponse A successful response from the server. - * @return {Bid[]} An array of bids which were nested inside the server. - */ interpretResponse: function (serverResponse) { const bids = []; logInfo('serverResponse: ', serverResponse); - _each(serverResponse.body.seatbid, function (bidSeatObject) { - logInfo('bidSeatObject: ', bidSeatObject); - _each(bidSeatObject.bid, function (bidObject) { - logInfo('bidObject: ', bidObject); - if (!bidObject.price || !bidObject.adm) { - return; - } - logInfo('CPM OK'); - const bid = getPrebidResponseBidObject(bidObject) - bids.push(bid); - }); + _each(serverResponse.body.bid, function (bidObject) { + logInfo('bidObject: ', bidObject); + if (!bidObject.price || !bidObject.adm) { + return; + } + logInfo('CPM OK'); + const bid = getPrebidResponseBidObject(bidObject) + bids.push(bid); }); - return bids; }, - /** - * Register bidder specific code, which will execute if a bid from this bidder won the auction - * @param {Bid} bid that won the auction - */ onBidWon: function(bid) { // Bidder specific code logInfo('onBidWon bid: ', bid); - const notice = buildWonBidNotice(bid) + const notice = buildWinNotice(bid) ajax(endpoints.notice.win, null, JSON.stringify(notice), { method: 'POST', withCredentials: true }); }, - /** - * Register bidder specific code, which will execute if bidder timed out after an auction - * - * @param {Array} data timeout specific data - */ onTimeout: (data) => { if (Array.isArray(data)) { const payload = buildTimeoutNotice(data) @@ -679,9 +498,6 @@ export const spec = { } }, - /** - * Register bidder specific code, which will execute if the bidder responded with an error - */ onBidderError: function({ bidderRequest }) { // Bidder specific code const notice = buildErrorNotice(bidderRequest) diff --git a/test/spec/modules/aidemBidAdapter_spec.js b/test/spec/modules/aidemBidAdapter_spec.js index ca542292be2..3ffb399522a 100644 --- a/test/spec/modules/aidemBidAdapter_spec.js +++ b/test/spec/modules/aidemBidAdapter_spec.js @@ -6,7 +6,6 @@ import {server} from '../../mocks/xhr'; import {config} from '../../../src/config'; import {NATIVE} from '../../../src/mediaTypes.js'; -// TODO implement more extensive VALID_BIDS // Full banner + Full Video + Basic Banner + Basic Video const VALID_BIDS = [ { @@ -40,7 +39,6 @@ const VALID_BIDS = [ }, ] -// TODO add some invalid requests const INVALID_BIDS = [ { bidder: 'aidem', @@ -86,36 +84,6 @@ const INVALID_BIDS = [ banner: {} }, }, - { - bidder: 'aidem', - mediaTypes: { - banner: { - sizes: [[300, 250], [300, 600]], - } - }, - params: { - siteId: '301491', - placementId: 13144370, - banner: { - size: [250, 250] - } - }, - }, - { - bidder: 'aidem', - mediaTypes: { - banner: { - sizes: [[300, 250], [300, 600]], - } - }, - params: { - siteId: '301491', - placementId: 13144370, - banner: { - size: '250x250' - } - }, - }, { bidder: 'aidem', mediaTypes: { @@ -234,35 +202,30 @@ const VALID_BIDDER_REQUEST = { const SERVER_RESPONSE_BANNER = { body: { id: 'efa1930a-bc3e-4fd0-8368-08bc40236b4f', - seatbid: [ + bid: [ + // BANNER { - bid: [ - // BANNER - { - 'id': '2e614be960ee1d', - 'impid': '2e614be960ee1d', - 'price': 7.91, - 'mediatype': 'banner', - 'adid': '24277955', - 'adm': 'creativity_banner', - 'adomain': [ - 'aidem.com' - ], - 'iurl': 'http://www.aidem.com', - 'cat': [], - 'cid': '4193561', - 'crid': '24277955', - 'w': 300, - 'h': 250, - 'ext': { - 'dspid': 85, - 'advbrandid': 1246, - 'advbrand': 'AIDEM' - } - }, + 'id': '2e614be960ee1d', + 'impid': '2e614be960ee1d', + 'price': 7.91, + 'mediatype': 'banner', + 'adid': '24277955', + 'adm': 'creativity_banner', + 'adomain': [ + 'aidem.com' ], - seat: '6047231' - } + 'iurl': 'http://www.aidem.com', + 'cat': [], + 'cid': '4193561', + 'crid': '24277955', + 'w': 300, + 'h': 250, + 'ext': { + 'dspid': 85, + 'advbrandid': 1246, + 'advbrand': 'AIDEM' + } + }, ], cur: 'USD' }, @@ -271,34 +234,29 @@ const SERVER_RESPONSE_BANNER = { const SERVER_RESPONSE_VIDEO = { body: { id: 'efa1930a-bc3e-4fd0-8368-08bc40236b4f', - seatbid: [ + bid: [ + // VIDEO { - bid: [ - // VIDEO - { - 'id': '2876a29392a47c', - 'impid': '2876a29392a47c', - 'price': 7.93, - 'mediatype': 'video', - 'adid': '24277955', - 'adm': 'https://hermes.aidemsrv.com/vast-tag/cl9mzhhd502uq09l720uegb02?auction_id={{AUCTION_ID}}&cachebuster={{CACHEBUSTER}}', - 'adomain': [ - 'aidem.com' - ], - 'iurl': 'http://www.aidem.com', - 'cat': [], - 'cid': '4193561', - 'crid': '24277955', - 'w': 640, - 'h': 480, - 'ext': { - 'dspid': 85, - 'advbrandid': 1246, - 'advbrand': 'AIDEM' - } - } + 'id': '2876a29392a47c', + 'impid': '2876a29392a47c', + 'price': 7.93, + 'mediatype': 'video', + 'adid': '24277955', + 'adm': 'https://hermes.aidemsrv.com/vast-tag/cl9mzhhd502uq09l720uegb02?auction_id={{AUCTION_ID}}&cachebuster={{CACHEBUSTER}}', + 'adomain': [ + 'aidem.com' ], - seat: '6047231' + 'iurl': 'http://www.aidem.com', + 'cat': [], + 'cid': '4193561', + 'crid': '24277955', + 'w': 640, + 'h': 480, + 'ext': { + 'dspid': 85, + 'advbrandid': 1246, + 'advbrand': 'AIDEM' + } } ], cur: 'USD' @@ -411,13 +369,6 @@ describe('Aidem adapter', () => { deepSetValue(validVideoRequest.params, 'video.size', [640, 480]) expect(spec.isBidRequestValid(validVideoRequest)).to.be.true }); - - it('should return false if params size is not an array', function () { - // spec.isBidRequestValid() - const validVideoRequest = utils.deepClone(VALID_BIDS[1]) - deepSetValue(validVideoRequest.params, 'video.size', [[300], [[300, 600]]]) - expect(spec.isBidRequestValid(validVideoRequest)).to.be.false - }); }); describe('buildRequests', () => { @@ -433,12 +384,12 @@ describe('Aidem adapter', () => { const requests = spec.buildRequests(DEFAULT_VALID_BANNER_REQUESTS, VALID_BIDDER_REQUEST); const payload = JSON.parse(requests.data) expect(payload).to.be.a('object').that.has.all.keys( - 'id', 'imp', 'mediaTypes', 'device', 'cur', 'tz', 'regs', 'site', 'environment', 'at', 'user' + 'id', 'imp', 'device', 'cur', 'tz', 'regs', 'site', 'environment', 'at' ) expect(payload.imp).to.be.a('array').that.has.lengthOf(DEFAULT_VALID_BANNER_REQUESTS.length) expect(payload.imp[0]).to.be.a('object').that.has.all.keys( - 'banner', 'id', 'mediatype', 'imp_ext', 'tid', 'siteId' + 'banner', 'id', 'mediatype', 'imp_ext', 'tid' ) expect(payload.imp[0].banner).to.be.a('object').that.has.all.keys( 'format', 'topframe' @@ -449,12 +400,12 @@ describe('Aidem adapter', () => { const requests = spec.buildRequests(DEFAULT_VALID_VIDEO_REQUESTS, VALID_BIDDER_REQUEST); const payload = JSON.parse(requests.data) expect(payload).to.be.a('object').that.has.all.keys( - 'id', 'imp', 'mediaTypes', 'device', 'cur', 'tz', 'regs', 'site', 'environment', 'at', 'user' + 'id', 'imp', 'device', 'cur', 'tz', 'regs', 'site', 'environment', 'at' ) expect(payload.imp).to.be.a('array').that.has.lengthOf(DEFAULT_VALID_VIDEO_REQUESTS.length) expect(payload.imp[0]).to.be.a('object').that.has.all.keys( - 'video', 'id', 'mediatype', 'imp_ext', 'tid', 'siteId' + 'video', 'id', 'mediatype', 'imp_ext', 'tid' ) expect(payload.imp[0].video).to.be.a('object').that.has.all.keys( 'format', 'mimes', 'minDuration', 'maxDuration', 'protocols' @@ -501,7 +452,7 @@ describe('Aidem adapter', () => { it('should return a valid bid array with netRevenue', () => { const response = utils.deepClone(SERVER_RESPONSE_BANNER) - response.body.seatbid[0].bid[0].isNet = true + response.body.bid[0].isNet = true const interpreted = spec.interpretResponse(response) expect(interpreted).to.be.a('array').that.has.lengthOf(1) expect(interpreted[0].netRevenue).to.be.true @@ -509,14 +460,14 @@ describe('Aidem adapter', () => { it('should return an empty bid array if one of seatbid entry is missing price property', () => { const response = utils.deepClone(SERVER_RESPONSE_BANNER) - delete response.body.seatbid[0].bid[0].price + delete response.body.bid[0].price const interpreted = spec.interpretResponse(response) expect(interpreted).to.be.a('array').that.has.lengthOf(0) }); it('should return an empty bid array if one of seatbid entry is missing adm property', () => { const response = utils.deepClone(SERVER_RESPONSE_BANNER) - delete response.body.seatbid[0].bid[0].adm + delete response.body.bid[0].adm const interpreted = spec.interpretResponse(response) expect(interpreted).to.be.a('array').that.has.lengthOf(0) }); @@ -549,7 +500,7 @@ describe('Aidem adapter', () => { const { bids } = JSON.parse(server.requests[0].requestBody) expect(bids).to.be.a('array').that.has.lengthOf(1) _each(bids, (bid) => { - expect(bid).to.be.a('object').that.has.all.keys('adUnitCode', 'auctionId', 'bidId', 'bidderRequestId', 'transactionId', 'metrics') + expect(bid).to.be.a('object').that.has.all.keys('adUnitCode', 'auctionId', 'bidId', 'bidderRequestId', 'transactionId') }) }); }); @@ -694,43 +645,13 @@ describe('Aidem adapter', () => { expect(request.device.connectiontype).to.equal(2) }); - it(`should populate prebidRequest site object`, function () { - config.setConfig({ - ortb2: { - site: { - name: 'example', - domain: 'page.example.com', - cat: ['IAB2'], - sectioncat: ['IAB2-2'], - pagecat: ['IAB2-2'], - keywords: 'power tools, drills', - ext: { - data: { // fields that aren't part of openrtb 2.5 - pageType: 'article', - category: 'repair' - } - } - }, - } - }); - const { data } = spec.buildRequests(DEFAULT_VALID_BANNER_REQUESTS, VALID_BIDDER_REQUEST); - const payload = JSON.parse(data) - // expect(payload.imp).to.be.a('array').that.has.lengthOf(1) - expect(payload.site).to.be.exist - const { site } = payload - expect(site).to.be.a('object').that.has.all.keys('cat', 'domain', 'page', 'referer', 'sectioncat', 'keywords', 'site_ext') - expect(site.cat).to.be.eql(['IAB2']) - expect(site.sectioncat).to.be.eql(['IAB2-2']) - expect(site.keywords).to.be.eql('power tools, drills') - }); - it(`should set coppa`, function () { config.setConfig({ coppa: true }); const { data } = spec.buildRequests(DEFAULT_VALID_BANNER_REQUESTS, VALID_BIDDER_REQUEST); const request = JSON.parse(data) - expect(request.regs.coppa).to.equal(true) + expect(request.regs.coppa_applies).to.equal(true) }); it(`should set gdpr to true`, function () { @@ -743,7 +664,7 @@ describe('Aidem adapter', () => { }); const { data } = spec.buildRequests(DEFAULT_VALID_BANNER_REQUESTS, VALID_BIDDER_REQUEST); const request = JSON.parse(data) - expect(request.regs.gdpr).to.equal(true) + expect(request.regs.gdpr_applies).to.equal(true) }); it(`should set usp_consent string`, function () { From 3c36ef245da449040716f4c67da009275c4ddef4 Mon Sep 17 00:00:00 2001 From: Giovanni Sollazzo Date: Mon, 14 Nov 2022 12:02:26 +0100 Subject: [PATCH 04/21] Fix Navigator in _spec.js --- test/spec/modules/aidemBidAdapter_spec.js | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/test/spec/modules/aidemBidAdapter_spec.js b/test/spec/modules/aidemBidAdapter_spec.js index 3ffb399522a..1e1dd2ec70f 100644 --- a/test/spec/modules/aidemBidAdapter_spec.js +++ b/test/spec/modules/aidemBidAdapter_spec.js @@ -625,26 +625,6 @@ describe('Aidem adapter', () => { expect(requestURL.host).to.equal('127.0.0.1:8787') }); - it(`should set correct connection default`, function () { - const { data } = spec.buildRequests(DEFAULT_VALID_BANNER_REQUESTS, VALID_BIDDER_REQUEST); - const request = JSON.parse(data) - expect(request.device.connectiontype).to.equal(0) - }); - - it(`should set correct connection type ethernet`, function () { - navigator.connection.type = 'ethernet' - const { data } = spec.buildRequests(DEFAULT_VALID_BANNER_REQUESTS, VALID_BIDDER_REQUEST); - const request = JSON.parse(data) - expect(request.device.connectiontype).to.equal(1) - }); - - it(`should set correct connection type wifi`, function () { - navigator.connection.type = 'wifi' - const { data } = spec.buildRequests(DEFAULT_VALID_BANNER_REQUESTS, VALID_BIDDER_REQUEST); - const request = JSON.parse(data) - expect(request.device.connectiontype).to.equal(2) - }); - it(`should set coppa`, function () { config.setConfig({ coppa: true From 502397ec864f5c74447edf74790e20690d617277 Mon Sep 17 00:00:00 2001 From: darkstar Date: Wed, 16 Nov 2022 18:19:49 +0100 Subject: [PATCH 05/21] Removed timeout handler. --- modules/aidemBidAdapter.js | 31 ++----------------- test/spec/modules/aidemBidAdapter_spec.js | 37 +---------------------- 2 files changed, 4 insertions(+), 64 deletions(-) diff --git a/modules/aidemBidAdapter.js b/modules/aidemBidAdapter.js index 91e64a6a807..dd67b7a36e6 100644 --- a/modules/aidemBidAdapter.js +++ b/modules/aidemBidAdapter.js @@ -153,6 +153,7 @@ function buildWinNotice(bid) { cpm: bid.cpm, currency: bid.currency, impid: deepAccess(bid, 'meta.impid'), + dsp_id: deepAccess(bid, 'meta.dsp_id'), adUnitCode: bid.adUnitCode, auctionId: bid.auctionId, transactionId: bid.transactionId, @@ -162,26 +163,6 @@ function buildWinNotice(bid) { } } -// Called for every bid that has timed out -function buildTimeoutNotice(prebidTimeoutBids) { - const timeoutNotice = { - bids: [] - } - _each(prebidTimeoutBids, function (bid) { - const notice = { - adUnitCode: bid.adUnitCode, - auctionId: bid.auctionId, - bidId: bid.bidId, - bidderRequestId: bid.bidderRequestId, - transactionId: bid.transactionId, - mediaTypes: bid.mediaTypes - } - timeoutNotice.bids.push(notice) - }) - - return timeoutNotice -} - function buildErrorNotice(prebidErrorResponse) { return { message: `Prebid.js: Server call for ${prebidErrorResponse.bidderCode} failed.`, @@ -352,6 +333,7 @@ function getPrebidResponseBidObject(openRTBResponseBidObject) { } function setPrebidResponseBidObjectMeta(prebidResponseBidObject, openRTBResponseBidObject) { + logInfo('AIDEM Bid Adapter meta', openRTBResponseBidObject); deepSetValue(prebidResponseBidObject, 'meta.advertiserDomains', openRTBResponseBidObject.adomain); if (openRTBResponseBidObject.cat && Array.isArray(openRTBResponseBidObject.cat)) { const primaryCatId = openRTBResponseBidObject.cat.shift(); @@ -359,6 +341,7 @@ function setPrebidResponseBidObjectMeta(prebidResponseBidObject, openRTBResponse deepSetValue(prebidResponseBidObject, 'meta.secondaryCatIds', openRTBResponseBidObject.cat); } deepSetValue(prebidResponseBidObject, 'meta.id', openRTBResponseBidObject.id); + deepSetValue(prebidResponseBidObject, 'meta.dsp_id', openRTBResponseBidObject.dsp_id); deepSetValue(prebidResponseBidObject, 'meta.adid', openRTBResponseBidObject.adid); deepSetValue(prebidResponseBidObject, 'meta.burl', openRTBResponseBidObject.burl); deepSetValue(prebidResponseBidObject, 'meta.impid', openRTBResponseBidObject.impid); @@ -490,14 +473,6 @@ export const spec = { ajax(endpoints.notice.win, null, JSON.stringify(notice), { method: 'POST', withCredentials: true }); }, - onTimeout: (data) => { - if (Array.isArray(data)) { - const payload = buildTimeoutNotice(data) - const payloadString = JSON.stringify(payload); - ajax(endpoints.notice.timeout, null, payloadString, { method: 'POST', withCredentials: true }); - } - }, - onBidderError: function({ bidderRequest }) { // Bidder specific code const notice = buildErrorNotice(bidderRequest) diff --git a/test/spec/modules/aidemBidAdapter_spec.js b/test/spec/modules/aidemBidAdapter_spec.js index 1e1dd2ec70f..d9a2be21948 100644 --- a/test/spec/modules/aidemBidAdapter_spec.js +++ b/test/spec/modules/aidemBidAdapter_spec.js @@ -1,7 +1,7 @@ import {expect} from 'chai'; import {setEndPoints, spec} from 'modules/aidemBidAdapter.js'; import * as utils from '../../../src/utils'; -import {_each, deepSetValue} from '../../../src/utils'; +import {deepSetValue} from '../../../src/utils'; import {server} from '../../mocks/xhr'; import {config} from '../../../src/config'; import {NATIVE} from '../../../src/mediaTypes.js'; @@ -300,23 +300,6 @@ const WIN_NOTICE = { } } -const TIMEOUT_NOTICE = [ - { - 'adUnitCode': 'div-gpt-ad-1460505748561-0', - 'auctionId': 'b57faab7-23f7-4b63-90db-67b259d20db7', - 'bidId': '233f0aa47ccb68', - 'bidderRequestId': '1c53857d1ce616', - 'transactionId': '5c09d600-6da1-4a66-8e97-a67ace3083a4', - metrics: { - getMetrics() { - return { - - } - } - } - } -] - const ERROR_NOTICE = { 'message': 'Prebid.js: Server call for aidem failed.', 'url': 'http%3A%2F%2Flocalhost%3A9999%2FintegrationExamples%2Fgpt%2Fhello_world.html%3Fpbjs_debug%3Dtrue', @@ -473,14 +456,12 @@ describe('Aidem adapter', () => { }); }) - // TODO verify that outgoing payload match expected structure describe('onBidWon', () => { it(`should exists and type function`, function () { expect(spec.onBidWon).to.exist.and.to.be.a('function') }); it(`should send a valid bid won notice`, function () { - // TODO check parameter after zero is working spec.onBidWon(WIN_NOTICE); // server.respondWith('POST', WIN_EVENT_URL, [ // 400, {'Content-Type': 'application/json'}, ) @@ -489,22 +470,6 @@ describe('Aidem adapter', () => { }); }); - describe('onTimeout', () => { - it(`should exists and type function`, function () { - expect(spec.onTimeout).to.exist.and.to.be.a('function') - }); - - it(`should send a valid timeout notice`, function () { - spec.onTimeout(TIMEOUT_NOTICE); - expect(server.requests.length).to.equal(1); - const { bids } = JSON.parse(server.requests[0].requestBody) - expect(bids).to.be.a('array').that.has.lengthOf(1) - _each(bids, (bid) => { - expect(bid).to.be.a('object').that.has.all.keys('adUnitCode', 'auctionId', 'bidId', 'bidderRequestId', 'transactionId') - }) - }); - }); - describe('onBidderError', () => { it(`should exists and type function`, function () { expect(spec.onBidderError).to.exist.and.to.be.a('function') From 9277d1ee2195161ffe30135ffdfc4d006ed54228 Mon Sep 17 00:00:00 2001 From: darkstar Date: Fri, 18 Nov 2022 15:06:10 +0100 Subject: [PATCH 06/21] Added publisherId as required bidder params --- modules/aidemBidAdapter.js | 10 ++++++++++ modules/aidemBidAdapter.md | 3 ++- test/spec/modules/aidemBidAdapter_spec.js | 15 ++++++++++++++- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/modules/aidemBidAdapter.js b/modules/aidemBidAdapter.js index dd67b7a36e6..f93f0d2dd49 100644 --- a/modules/aidemBidAdapter.js +++ b/modules/aidemBidAdapter.js @@ -20,6 +20,7 @@ export const ERROR_CODES = { PROPERTY_NOT_INCLUDED: 3, SITE_ID_INVALID_VALUE: 4, MEDIA_TYPE_NOT_SUPPORTED: 5, + PUBLISHER_ID_INVALID_VALUE: 6, }; const endpoints = { @@ -219,6 +220,8 @@ function setPrebidImpressionObject(bidRequests, payload) { deepSetValue(impressionObject, 'id', bidRequest.bidId); // Transaction id deepSetValue(impressionObject, 'tid', deepAccess(bidRequest, 'transactionId')); + // Publisher id + deepSetValue(payload, 'site.publisher_id', deepAccess(bidRequest, 'params.publisherId')); // Site id deepSetValue(payload, 'site.id', deepAccess(bidRequest, 'params.siteId')); const mediaType = getMediaType(bidRequest) @@ -402,11 +405,18 @@ function hasValidVideoParameters(bidRequest) { function hasValidParameters(bidRequest) { // Assigned from AIDEM to a publisher website const siteId = deepAccess(bidRequest, 'params.siteId'); + const publisherId = deepAccess(bidRequest, 'params.publisherId'); + if (!isStr(siteId)) { logError('AIDEM Bid Adapter: siteId must valid string', { bidder: BIDDER_CODE, code: ERROR_CODES.SITE_ID_INVALID_VALUE }); return false; } + if (!isStr(publisherId)) { + logError('AIDEM Bid Adapter: publisherId must valid string', { bidder: BIDDER_CODE, code: ERROR_CODES.PUBLISHER_ID_INVALID_VALUE }); + return false; + } + return true } diff --git a/modules/aidemBidAdapter.md b/modules/aidemBidAdapter.md index 7d397239bc1..a5beca97d10 100644 --- a/modules/aidemBidAdapter.md +++ b/modules/aidemBidAdapter.md @@ -17,6 +17,7 @@ This module is GDPR and CCPA compliant, and no 3rd party userIds are allowed. | Name | Scope | Description | Example | Type | |---------------|----------|---------------------|---------------|----------| | `siteId` | required | Unique site ID | `'ABCDEF'` | `String` | +| `publisherId` | required | Unique publisher ID | `'ABCDEF'` | `String` | ### Banner Bid Params @@ -183,4 +184,4 @@ For video: gulp serve --modules=aidemBidAdapter,dfpAdServerVideo # FAQs ### How do I view AIDEM bid request? Navigate to a page where AIDEM is setup to bid. In the network tab, -search for requests to `zero.aidemsrv.com/bid/request`. \ No newline at end of file +search for requests to `zero.aidemsrv.com/bid/request`. diff --git a/test/spec/modules/aidemBidAdapter_spec.js b/test/spec/modules/aidemBidAdapter_spec.js index d9a2be21948..472b226ab8a 100644 --- a/test/spec/modules/aidemBidAdapter_spec.js +++ b/test/spec/modules/aidemBidAdapter_spec.js @@ -12,6 +12,7 @@ const VALID_BIDS = [ bidder: 'aidem', params: { siteId: '301491', + publisherId: '3021491', placementId: 13144370, }, mediaTypes: { @@ -24,6 +25,7 @@ const VALID_BIDS = [ bidder: 'aidem', params: { siteId: '301491', + publisherId: '3021491', placementId: 13144370, }, mediaTypes: { @@ -54,7 +56,18 @@ const INVALID_BIDS = [ } }, params: { - siteId: undefined + siteId: '3014912', + } + }, + { + bidder: 'aidem', + mediaTypes: { + banner: { + sizes: [[300, 250], [300, 600]], + } + }, + params: { + publisherId: '3014912', } }, { From 31d6b229c24c961104c1f36e836704135898e4d1 Mon Sep 17 00:00:00 2001 From: darkstar Date: Fri, 18 Nov 2022 17:34:08 +0100 Subject: [PATCH 07/21] moved publisherId into site publisher object --- modules/aidemBidAdapter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/aidemBidAdapter.js b/modules/aidemBidAdapter.js index f93f0d2dd49..41bf680db1c 100644 --- a/modules/aidemBidAdapter.js +++ b/modules/aidemBidAdapter.js @@ -221,7 +221,7 @@ function setPrebidImpressionObject(bidRequests, payload) { // Transaction id deepSetValue(impressionObject, 'tid', deepAccess(bidRequest, 'transactionId')); // Publisher id - deepSetValue(payload, 'site.publisher_id', deepAccess(bidRequest, 'params.publisherId')); + deepSetValue(payload, 'site.publisher.id', deepAccess(bidRequest, 'params.publisherId')); // Site id deepSetValue(payload, 'site.id', deepAccess(bidRequest, 'params.siteId')); const mediaType = getMediaType(bidRequest) From 705f255e683d5d83de539614af741aa5a29f1e58 Mon Sep 17 00:00:00 2001 From: Giovanni Sollazzo Date: Tue, 27 Dec 2022 00:41:15 +0100 Subject: [PATCH 08/21] Added wpar to environment --- modules/aidemBidAdapter.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/aidemBidAdapter.js b/modules/aidemBidAdapter.js index 41bf680db1c..086d1f3bc37 100644 --- a/modules/aidemBidAdapter.js +++ b/modules/aidemBidAdapter.js @@ -265,6 +265,8 @@ function setPrebidRequestEnvironment(payload) { deepSetValue(payload, 'environment.inp.jp', window.JSON.parse.name === 'parse' && typeof window.JSON.parse.prototype === 'undefined'); deepSetValue(payload, 'environment.inp.ofe', window.Object.fromEntries.name === 'fromEntries' && typeof window.Object.fromEntries.prototype === 'undefined'); deepSetValue(payload, 'environment.inp.oa', window.Object.assign.name === 'assign' && typeof window.Object.assign.prototype === 'undefined'); + deepSetValue(payload, 'environment.wpar.innerWidth', window.innerWidth); + deepSetValue(payload, 'environment.wpar.innerHeight', window.innerHeight); } function setPrebidImpressionObjectFloor(bidRequest, impressionObject) { From 3a319eed2e4b01063f6c4f721de2f2183e657648 Mon Sep 17 00:00:00 2001 From: Giovanni Sollazzo Date: Wed, 28 Dec 2022 13:04:09 +0100 Subject: [PATCH 09/21] Added placementId parameter --- modules/aidemBidAdapter.js | 2 ++ modules/aidemBidAdapter.md | 1 + test/spec/modules/aidemBidAdapter_spec.js | 4 ++-- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/modules/aidemBidAdapter.js b/modules/aidemBidAdapter.js index 086d1f3bc37..081a0324ddb 100644 --- a/modules/aidemBidAdapter.js +++ b/modules/aidemBidAdapter.js @@ -220,6 +220,8 @@ function setPrebidImpressionObject(bidRequests, payload) { deepSetValue(impressionObject, 'id', bidRequest.bidId); // Transaction id deepSetValue(impressionObject, 'tid', deepAccess(bidRequest, 'transactionId')); + // Placement id + deepSetValue(impressionObject, 'tagid', deepAccess(bidRequest, 'params.placementId', null)); // Publisher id deepSetValue(payload, 'site.publisher.id', deepAccess(bidRequest, 'params.publisherId')); // Site id diff --git a/modules/aidemBidAdapter.md b/modules/aidemBidAdapter.md index a5beca97d10..342a264da01 100644 --- a/modules/aidemBidAdapter.md +++ b/modules/aidemBidAdapter.md @@ -18,6 +18,7 @@ This module is GDPR and CCPA compliant, and no 3rd party userIds are allowed. |---------------|----------|---------------------|---------------|----------| | `siteId` | required | Unique site ID | `'ABCDEF'` | `String` | | `publisherId` | required | Unique publisher ID | `'ABCDEF'` | `String` | +| `placementId` | optional | Unique publisher tag ID | `'ABCDEF'` | `String` | ### Banner Bid Params diff --git a/test/spec/modules/aidemBidAdapter_spec.js b/test/spec/modules/aidemBidAdapter_spec.js index 472b226ab8a..64122ad69f0 100644 --- a/test/spec/modules/aidemBidAdapter_spec.js +++ b/test/spec/modules/aidemBidAdapter_spec.js @@ -385,7 +385,7 @@ describe('Aidem adapter', () => { expect(payload.imp).to.be.a('array').that.has.lengthOf(DEFAULT_VALID_BANNER_REQUESTS.length) expect(payload.imp[0]).to.be.a('object').that.has.all.keys( - 'banner', 'id', 'mediatype', 'imp_ext', 'tid' + 'banner', 'id', 'mediatype', 'imp_ext', 'tid', 'tagid' ) expect(payload.imp[0].banner).to.be.a('object').that.has.all.keys( 'format', 'topframe' @@ -401,7 +401,7 @@ describe('Aidem adapter', () => { expect(payload.imp).to.be.a('array').that.has.lengthOf(DEFAULT_VALID_VIDEO_REQUESTS.length) expect(payload.imp[0]).to.be.a('object').that.has.all.keys( - 'video', 'id', 'mediatype', 'imp_ext', 'tid' + 'video', 'id', 'mediatype', 'imp_ext', 'tid', 'tagid' ) expect(payload.imp[0].video).to.be.a('object').that.has.all.keys( 'format', 'mimes', 'minDuration', 'maxDuration', 'protocols' From f70425560f7ca32592ae0c8fa55cc2730ff5b0c4 Mon Sep 17 00:00:00 2001 From: darkstar Date: Mon, 2 Jan 2023 15:32:36 +0100 Subject: [PATCH 10/21] added unit tests for the wpar environment object --- test/spec/modules/aidemBidAdapter_spec.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/spec/modules/aidemBidAdapter_spec.js b/test/spec/modules/aidemBidAdapter_spec.js index 64122ad69f0..71edfcf82fb 100644 --- a/test/spec/modules/aidemBidAdapter_spec.js +++ b/test/spec/modules/aidemBidAdapter_spec.js @@ -421,6 +421,14 @@ describe('Aidem adapter', () => { 'value', 'currency' ) }); + + it('should hav wpar keys in environment object', function () { + const requests = spec.buildRequests(DEFAULT_VALID_VIDEO_REQUESTS, VALID_BIDDER_REQUEST); + const payload = JSON.parse(requests.data) + expect(payload).to.have.property('environment') + expect(payload.environment).to.be.a('object').that.have.property('wpar') + expect(payload.environment.wpar).to.be.a('object').that.has.keys('innerWidth', 'innerHeight') + }); }) describe('interpretResponse', () => { From f077631d937990e99813dd87d640b34560ed0d3c Mon Sep 17 00:00:00 2001 From: darkstar Date: Tue, 24 Jan 2023 20:33:22 +0100 Subject: [PATCH 11/21] PlacementId is now a required parameter Added optional rateLimit parameter Added publisherId, siteId, placementId in win notice payload Added unit tests --- modules/aidemBidAdapter.js | 39 ++++++++- modules/aidemBidAdapter.md | 19 +++-- test/spec/modules/aidemBidAdapter_spec.js | 97 ++++++++++++++++++++--- 3 files changed, 135 insertions(+), 20 deletions(-) diff --git a/modules/aidemBidAdapter.js b/modules/aidemBidAdapter.js index 081a0324ddb..873cb3061f2 100644 --- a/modules/aidemBidAdapter.js +++ b/modules/aidemBidAdapter.js @@ -1,4 +1,4 @@ -import {_each, contains, deepAccess, deepSetValue, getDNT, isBoolean, isStr, logError, logInfo} from '../src/utils.js'; +import {_each, contains, deepAccess, deepSetValue, getDNT, isBoolean, isStr, isNumber, logError, logInfo} from '../src/utils.js'; import {config} from '../src/config.js'; import {BANNER, VIDEO} from '../src/mediaTypes.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; @@ -21,6 +21,8 @@ export const ERROR_CODES = { SITE_ID_INVALID_VALUE: 4, MEDIA_TYPE_NOT_SUPPORTED: 5, PUBLISHER_ID_INVALID_VALUE: 6, + INVALID_RATELIMIT: 7, + PLACEMENT_ID_INVALID_VALUE: 8, }; const endpoints = { @@ -149,7 +151,11 @@ function getPageUrl(bidderRequest) { } function buildWinNotice(bid) { + const params = bid.params[0] return { + publisherId: params.publisherId, + siteId: params.siteId, + placementId: params.placementId, burl: deepAccess(bid, 'meta.burl'), cpm: bid.cpm, currency: bid.currency, @@ -220,7 +226,7 @@ function setPrebidImpressionObject(bidRequests, payload) { deepSetValue(impressionObject, 'id', bidRequest.bidId); // Transaction id deepSetValue(impressionObject, 'tid', deepAccess(bidRequest, 'transactionId')); - // Placement id + // placement id deepSetValue(impressionObject, 'tagid', deepAccess(bidRequest, 'params.placementId', null)); // Publisher id deepSetValue(payload, 'site.publisher.id', deepAccess(bidRequest, 'params.publisherId')); @@ -341,7 +347,7 @@ function getPrebidResponseBidObject(openRTBResponseBidObject) { function setPrebidResponseBidObjectMeta(prebidResponseBidObject, openRTBResponseBidObject) { logInfo('AIDEM Bid Adapter meta', openRTBResponseBidObject); - deepSetValue(prebidResponseBidObject, 'meta.advertiserDomains', openRTBResponseBidObject.adomain); + deepSetValue(prebidResponseBidObject, 'meta.advertiserDomains', deepAccess(openRTBResponseBidObject, 'meta.advertiserDomains')); if (openRTBResponseBidObject.cat && Array.isArray(openRTBResponseBidObject.cat)) { const primaryCatId = openRTBResponseBidObject.cat.shift(); deepSetValue(prebidResponseBidObject, 'meta.primaryCatId', primaryCatId); @@ -406,10 +412,26 @@ function hasValidVideoParameters(bidRequest) { return valid } +function passesRateLimit(bidRequest) { + const rateLimit = deepAccess(bidRequest, 'params.rateLimit', 1); + if (!isNumber(rateLimit) || rateLimit > 1 || rateLimit < 0) { + logError('AIDEM Bid Adapter: invalid rateLimit (must be a number between 0 and 1)', { bidder: BIDDER_CODE, code: ERROR_CODES.INVALID_RATELIMIT }); + return false + } + if (rateLimit !== 1) { + const randomRateValue = Math.random() + if (randomRateValue > rateLimit) { + return false + } + } + return true +} + function hasValidParameters(bidRequest) { // Assigned from AIDEM to a publisher website const siteId = deepAccess(bidRequest, 'params.siteId'); const publisherId = deepAccess(bidRequest, 'params.publisherId'); + const placementId = deepAccess(bidRequest, 'params.placementId'); if (!isStr(siteId)) { logError('AIDEM Bid Adapter: siteId must valid string', { bidder: BIDDER_CODE, code: ERROR_CODES.SITE_ID_INVALID_VALUE }); @@ -421,6 +443,11 @@ function hasValidParameters(bidRequest) { return false; } + if (!isStr(placementId)) { + logError('AIDEM Bid Adapter: placementId must valid string', { bidder: BIDDER_CODE, code: ERROR_CODES.PLACEMENT_ID_INVALID_VALUE }); + return false; + } + return true } @@ -446,7 +473,11 @@ export const spec = { return false } - return hasValidParameters(bidRequest) + if (!hasValidParameters(bidRequest)) { + return false + } + + return passesRateLimit(bidRequest) }, buildRequests: function(validBidRequests, bidderRequest) { diff --git a/modules/aidemBidAdapter.md b/modules/aidemBidAdapter.md index 342a264da01..76694f62f63 100644 --- a/modules/aidemBidAdapter.md +++ b/modules/aidemBidAdapter.md @@ -14,11 +14,12 @@ This module is GDPR and CCPA compliant, and no 3rd party userIds are allowed. ## Global Bid Params -| Name | Scope | Description | Example | Type | -|---------------|----------|---------------------|---------------|----------| -| `siteId` | required | Unique site ID | `'ABCDEF'` | `String` | -| `publisherId` | required | Unique publisher ID | `'ABCDEF'` | `String` | -| `placementId` | optional | Unique publisher tag ID | `'ABCDEF'` | `String` | +| Name | Scope | Description | Example | Type | +|---------------|----------|-------------------------|------------|----------| +| `siteId` | required | Unique site ID | `'ABCDEF'` | `String` | +| `publisherId` | required | Unique publisher ID | `'ABCDEF'` | `String` | +| `placementId` | required | Unique publisher tag ID | `'ABCDEF'` | `String` | +| `rateLimit` | optional | Limit the volume sent to AIDEM. Must be between 0 and 1 | `0.6` | `Number` | ### Banner Bid Params @@ -67,7 +68,9 @@ var adUnits = [{ bids: [{ bidder: 'aidem', params: { - siteId: 'prebid-test-site', + placementId: 'prebid-test-placementId', + siteId: 'prebid-test-siteId', + publisherId: 'prebid-test-publisherId', }, }] }]; @@ -90,7 +93,9 @@ var adUnits = [{ bids: [{ bidder: 'aidem', params: { - siteId: 'prebid-test-site', + placementId: 'prebid-test-placementId', + siteId: 'prebid-test-siteId', + publisherId: 'prebid-test-publisherId', }, }] }]; diff --git a/test/spec/modules/aidemBidAdapter_spec.js b/test/spec/modules/aidemBidAdapter_spec.js index 71edfcf82fb..2d7a8971c9c 100644 --- a/test/spec/modules/aidemBidAdapter_spec.js +++ b/test/spec/modules/aidemBidAdapter_spec.js @@ -13,7 +13,7 @@ const VALID_BIDS = [ params: { siteId: '301491', publisherId: '3021491', - placementId: 13144370, + placementId: '13144370', }, mediaTypes: { banner: { @@ -26,7 +26,7 @@ const VALID_BIDS = [ params: { siteId: '301491', publisherId: '3021491', - placementId: 13144370, + placementId: '13144370', }, mediaTypes: { video: { @@ -59,6 +59,18 @@ const INVALID_BIDS = [ siteId: '3014912', } }, + { + bidder: 'aidem', + mediaTypes: { + banner: { + sizes: [[300, 250], [300, 600]], + } + }, + params: { + publisherId: '3014912', + siteId: '3014912', + } + }, { bidder: 'aidem', mediaTypes: { @@ -110,7 +122,7 @@ const INVALID_BIDS = [ }, params: { siteId: '301491', - placementId: 13144370, + placementId: '13144370', }, }, { @@ -126,7 +138,7 @@ const INVALID_BIDS = [ }, params: { siteId: '301491', - placementId: 13144370, + placementId: '13144370', }, }, { @@ -143,7 +155,7 @@ const INVALID_BIDS = [ }, params: { siteId: '301491', - placementId: 13144370, + placementId: '13144370', video: { size: [480, 40] } @@ -167,8 +179,8 @@ const DEFAULT_VALID_BANNER_REQUESTS = [ } }, params: { - siteId: 1, - placementId: 13144370 + siteId: '1', + placementId: '13144370' }, src: 'client', transactionId: '54a58774-7a41-494e-9aaf-fa7b79164f0c' @@ -192,8 +204,8 @@ const DEFAULT_VALID_VIDEO_REQUESTS = [ } }, params: { - siteId: 1, - placementId: 13144370 + siteId: '1', + placementId: '13144370' }, src: 'client', transactionId: '54a58774-7a41-494e-9aaf-fa7b79164f0c' @@ -291,12 +303,23 @@ const WIN_NOTICE = { 'hb_format': 'banner', 'hb_adomain': 'tenutabene.it' }, + 'auctionId': '85864730-6cbc-4e56-bc3c-a4a6596dca5b', 'currency': [ 'USD' ], 'mediaType': 'banner', + 'advertiserDomains': [ + 'abc.com' + ], 'size': '300x250', + 'params': [ + { + 'placementId': '13144370', + 'siteId': '23434', + 'publisherId': '7689670753' + } + ], 'width': 300, 'height': 250, 'status': 'rendered', @@ -365,6 +388,62 @@ describe('Aidem adapter', () => { deepSetValue(validVideoRequest.params, 'video.size', [640, 480]) expect(spec.isBidRequestValid(validVideoRequest)).to.be.true }); + + it('BANNER: should return true if rateLimit is 1', function () { + // spec.isBidRequestValid() + const validBannerRequest = utils.deepClone(VALID_BIDS[0]) + deepSetValue(validBannerRequest.params, 'rateLimit', 1) + expect(spec.isBidRequestValid(validBannerRequest)).to.be.true + }); + + it('BANNER: should return false if rateLimit is 0', function () { + // spec.isBidRequestValid() + const validBannerRequest = utils.deepClone(VALID_BIDS[0]) + deepSetValue(validBannerRequest.params, 'rateLimit', 0) + expect(spec.isBidRequestValid(validBannerRequest)).to.be.false + }); + + it('BANNER: should return false if rateLimit is not between 0 and 1', function () { + // spec.isBidRequestValid() + const validBannerRequest = utils.deepClone(VALID_BIDS[0]) + deepSetValue(validBannerRequest.params, 'rateLimit', 1.2) + expect(spec.isBidRequestValid(validBannerRequest)).to.be.false + }); + + it('BANNER: should return false if rateLimit is not a number', function () { + // spec.isBidRequestValid() + const validBannerRequest = utils.deepClone(VALID_BIDS[0]) + deepSetValue(validBannerRequest.params, 'rateLimit', '0.5') + expect(spec.isBidRequestValid(validBannerRequest)).to.be.false + }); + + it('VIDEO: should return true if rateLimit is 1', function () { + // spec.isBidRequestValid() + const validVideoRequest = utils.deepClone(VALID_BIDS[1]) + deepSetValue(validVideoRequest.params, 'rateLimit', 1) + expect(spec.isBidRequestValid(validVideoRequest)).to.be.true + }); + + it('VIDEO: should return false if rateLimit is 0', function () { + // spec.isBidRequestValid() + const validVideoRequest = utils.deepClone(VALID_BIDS[1]) + deepSetValue(validVideoRequest.params, 'rateLimit', 0) + expect(spec.isBidRequestValid(validVideoRequest)).to.be.false + }); + + it('VIDEO: should return false if rateLimit is not between 0 and 1', function () { + // spec.isBidRequestValid() + const validBannerRequest = utils.deepClone(VALID_BIDS[1]) + deepSetValue(validBannerRequest.params, 'rateLimit', 1.2) + expect(spec.isBidRequestValid(validBannerRequest)).to.be.false + }); + + it('VIDEO: should return false if rateLimit is not a number', function () { + // spec.isBidRequestValid() + const validBannerRequest = utils.deepClone(VALID_BIDS[1]) + deepSetValue(validBannerRequest.params, 'rateLimit', '0.5') + expect(spec.isBidRequestValid(validBannerRequest)).to.be.false + }); }); describe('buildRequests', () => { From 4d67382f1fe65f4ca20d6c6909bf7b61517f54d3 Mon Sep 17 00:00:00 2001 From: darkstar Date: Mon, 30 Jan 2023 12:22:31 +0100 Subject: [PATCH 12/21] Revert to optional placementId parameter Added missing semicolons --- modules/aidemBidAdapter.js | 142 +++++++++++----------- modules/aidemBidAdapter.md | 4 +- test/spec/modules/aidemBidAdapter_spec.js | 14 +-- 3 files changed, 70 insertions(+), 90 deletions(-) diff --git a/modules/aidemBidAdapter.js b/modules/aidemBidAdapter.js index 873cb3061f2..e4d5c618b77 100644 --- a/modules/aidemBidAdapter.js +++ b/modules/aidemBidAdapter.js @@ -32,29 +32,29 @@ const endpoints = { timeout: `${BASE_URL}/notice/timeout`, error: `${BASE_URL}/notice/error`, } -} +}; export function setEndPoints(env = null, path = '', mediaType = BANNER) { switch (env) { case 'local': - endpoints.request = mediaType === BANNER ? `${LOCAL_BASE_URL}${path}/bid/request` : `${LOCAL_BASE_URL}${path}/bid/videorequest` - endpoints.notice.win = `${LOCAL_BASE_URL}${path}/notice/win` - endpoints.notice.error = `${LOCAL_BASE_URL}${path}/notice/error` - endpoints.notice.timeout = `${LOCAL_BASE_URL}${path}/notice/timeout` + endpoints.request = mediaType === BANNER ? `${LOCAL_BASE_URL}${path}/bid/request` : `${LOCAL_BASE_URL}${path}/bid/videorequest`; + endpoints.notice.win = `${LOCAL_BASE_URL}${path}/notice/win`; + endpoints.notice.error = `${LOCAL_BASE_URL}${path}/notice/error`; + endpoints.notice.timeout = `${LOCAL_BASE_URL}${path}/notice/timeout`; break; case 'main': - endpoints.request = mediaType === BANNER ? `${BASE_URL}${path}/bid/request` : `${BASE_URL}${path}/bid/videorequest` - endpoints.notice.win = `${BASE_URL}${path}/notice/win` - endpoints.notice.error = `${BASE_URL}${path}/notice/error` - endpoints.notice.timeout = `${BASE_URL}${path}/notice/timeout` + endpoints.request = mediaType === BANNER ? `${BASE_URL}${path}/bid/request` : `${BASE_URL}${path}/bid/videorequest`; + endpoints.notice.win = `${BASE_URL}${path}/notice/win`; + endpoints.notice.error = `${BASE_URL}${path}/notice/error`; + endpoints.notice.timeout = `${BASE_URL}${path}/notice/timeout`; break; } - return endpoints + return endpoints; } config.getConfig('aidem', function (config) { - if (config.aidem.env) { setEndPoints(config.aidem.env, config.aidem.path, config.aidem.mediaType) } -}) + if (config.aidem.env) { setEndPoints(config.aidem.env, config.aidem.path, config.aidem.mediaType); } +}); // AIDEM Custom FN function recur(obj) { @@ -123,8 +123,8 @@ function getDevice() { function getRegs() { let regs = {}; - const consentManagement = config.getConfig('consentManagement') - const coppa = config.getConfig('coppa') + const consentManagement = config.getConfig('consentManagement'); + const coppa = config.getConfig('coppa'); if (consentManagement && !!(consentManagement.gdpr)) { deepSetValue(regs, 'gdpr_applies', !!consentManagement.gdpr); } else { @@ -147,11 +147,11 @@ function getRegs() { } function getPageUrl(bidderRequest) { - return bidderRequest?.refererInfo?.page + return bidderRequest?.refererInfo?.page; } function buildWinNotice(bid) { - const params = bid.params[0] + const params = bid.params[0]; return { publisherId: params.publisherId, siteId: params.siteId, @@ -167,7 +167,7 @@ function buildWinNotice(bid) { ttl: bid.ttl, requestTimestamp: bid.requestTimestamp, responseTimestamp: bid.responseTimestamp, - } + }; } function buildErrorNotice(prebidErrorResponse) { @@ -177,29 +177,29 @@ function buildErrorNotice(prebidErrorResponse) { auctionId: prebidErrorResponse.auctionId, bidderRequestId: prebidErrorResponse.bidderRequestId, metrics: {} - } + }; } function hasValidFloor(obj) { - if (!obj) return false - const hasValue = !isNaN(Number(obj.value)) - const hasCurrency = contains(AVAILABLE_CURRENCIES, obj.currency) - return hasValue && hasCurrency + if (!obj) return false; + const hasValue = !isNaN(Number(obj.value)); + const hasCurrency = contains(AVAILABLE_CURRENCIES, obj.currency); + return hasValue && hasCurrency; } function getMediaType(bidRequest) { - if ((bidRequest.mediaTypes && bidRequest.mediaTypes.hasOwnProperty('video')) || bidRequest.params.hasOwnProperty('video')) { return VIDEO } - return BANNER + if ((bidRequest.mediaTypes && bidRequest.mediaTypes.hasOwnProperty('video')) || bidRequest.params.hasOwnProperty('video')) { return VIDEO; } + return BANNER; } function getPrebidRequestFields(bidderRequest, bidRequests) { - const payload = {} + const payload = {}; // Base Payload Data deepSetValue(payload, 'id', bidderRequest.auctionId); // Impressions - setPrebidImpressionObject(bidRequests, payload) + setPrebidImpressionObject(bidRequests, payload); // Device - deepSetValue(payload, 'device', getDevice()) + deepSetValue(payload, 'device', getDevice()); // Timeout deepSetValue(payload, 'tmax', bidderRequest.timeout); // Currency @@ -209,13 +209,13 @@ function getPrebidRequestFields(bidderRequest, bidRequests) { // Privacy Regs deepSetValue(payload, 'regs', getRegs()); // Site - setPrebidSiteObject(bidderRequest, payload) + setPrebidSiteObject(bidderRequest, payload); // Environment - setPrebidRequestEnvironment(payload) + setPrebidRequestEnvironment(payload); // AT auction type deepSetValue(payload, 'at', 1); - return payload + return payload; } function setPrebidImpressionObject(bidRequests, payload) { @@ -232,18 +232,18 @@ function setPrebidImpressionObject(bidRequests, payload) { deepSetValue(payload, 'site.publisher.id', deepAccess(bidRequest, 'params.publisherId')); // Site id deepSetValue(payload, 'site.id', deepAccess(bidRequest, 'params.siteId')); - const mediaType = getMediaType(bidRequest) + const mediaType = getMediaType(bidRequest); switch (mediaType) { case 'banner': - setPrebidImpressionObjectBanner(bidRequest, impressionObject) + setPrebidImpressionObjectBanner(bidRequest, impressionObject); break; case 'video': - setPrebidImpressionObjectVideo(bidRequest, impressionObject) + setPrebidImpressionObjectVideo(bidRequest, impressionObject); break; } // Floor (optional) - setPrebidImpressionObjectFloor(bidRequest, impressionObject) + setPrebidImpressionObjectFloor(bidRequest, impressionObject); impressionObject.imp_ext = {}; @@ -278,10 +278,10 @@ function setPrebidRequestEnvironment(payload) { } function setPrebidImpressionObjectFloor(bidRequest, impressionObject) { - const floor = deepAccess(bidRequest, 'params.floor') + const floor = deepAccess(bidRequest, 'params.floor'); if (hasValidFloor(floor)) { - deepSetValue(impressionObject, 'floor.value', floor.value) - deepSetValue(impressionObject, 'floor.currency', floor.currency) + deepSetValue(impressionObject, 'floor.value', floor.value); + deepSetValue(impressionObject, 'floor.currency', floor.currency); } } @@ -328,7 +328,7 @@ function getPrebidResponseBidObject(openRTBResponseBidObject) { deepSetValue(prebidResponseBidObject, 'currency', openRTBResponseBidObject.cur ? openRTBResponseBidObject.cur.toUpperCase() : DEFAULT_CURRENCY); deepSetValue(prebidResponseBidObject, 'width', openRTBResponseBidObject.w); deepSetValue(prebidResponseBidObject, 'height', openRTBResponseBidObject.h); - deepSetValue(prebidResponseBidObject, 'dealId', openRTBResponseBidObject.dealid) + deepSetValue(prebidResponseBidObject, 'dealId', openRTBResponseBidObject.dealid); deepSetValue(prebidResponseBidObject, 'netRevenue', true); deepSetValue(prebidResponseBidObject, 'ttl', 60000); @@ -341,8 +341,8 @@ function getPrebidResponseBidObject(openRTBResponseBidObject) { deepSetValue(prebidResponseBidObject, 'mediaType', BANNER); deepSetValue(prebidResponseBidObject, 'ad', openRTBResponseBidObject.adm); } - setPrebidResponseBidObjectMeta(prebidResponseBidObject, openRTBResponseBidObject) - return prebidResponseBidObject + setPrebidResponseBidObjectMeta(prebidResponseBidObject, openRTBResponseBidObject); + return prebidResponseBidObject; } function setPrebidResponseBidObjectMeta(prebidResponseBidObject, openRTBResponseBidObject) { @@ -363,28 +363,28 @@ function setPrebidResponseBidObjectMeta(prebidResponseBidObject, openRTBResponse } function hasValidMediaType(bidRequest) { - const supported = hasBannerMediaType(bidRequest) || hasVideoMediaType(bidRequest) + const supported = hasBannerMediaType(bidRequest) || hasVideoMediaType(bidRequest); if (!supported) { logError('AIDEM Bid Adapter: media type not supported', { bidder: BIDDER_CODE, code: ERROR_CODES.MEDIA_TYPE_NOT_SUPPORTED }); } - return supported + return supported; } function hasBannerMediaType(bidRequest) { - return !!deepAccess(bidRequest, 'mediaTypes.banner') + return !!deepAccess(bidRequest, 'mediaTypes.banner'); } function hasVideoMediaType(bidRequest) { - return !!deepAccess(bidRequest, 'mediaTypes.video') + return !!deepAccess(bidRequest, 'mediaTypes.video'); } function hasValidBannerMediaType(bidRequest) { - const sizes = deepAccess(bidRequest, 'mediaTypes.banner.sizes') + const sizes = deepAccess(bidRequest, 'mediaTypes.banner.sizes'); if (!sizes) { logError('AIDEM Bid Adapter: media type sizes missing', { bidder: BIDDER_CODE, code: ERROR_CODES.PROPERTY_NOT_INCLUDED }); return false; } - return true + return true; } function hasValidVideoMediaType(bidRequest) { @@ -393,45 +393,44 @@ function hasValidVideoMediaType(bidRequest) { logError('AIDEM Bid Adapter: media type playerSize missing', { bidder: BIDDER_CODE, code: ERROR_CODES.PROPERTY_NOT_INCLUDED }); return false; } - return true + return true; } function hasValidVideoParameters(bidRequest) { - let valid = true + let valid = true; const adUnitsParameters = deepAccess(bidRequest, 'mediaTypes.video'); const bidderParameter = deepAccess(bidRequest, 'params.video'); for (let property of REQUIRED_VIDEO_PARAMS) { - const hasAdUnitParameter = adUnitsParameters.hasOwnProperty(property) - const hasBidderParameter = bidderParameter && bidderParameter.hasOwnProperty(property) + const hasAdUnitParameter = adUnitsParameters.hasOwnProperty(property); + const hasBidderParameter = bidderParameter && bidderParameter.hasOwnProperty(property); if (!hasAdUnitParameter && !hasBidderParameter) { logError(`AIDEM Bid Adapter: ${property} is not included in either the adunit or params level`, { bidder: BIDDER_CODE, code: ERROR_CODES.PROPERTY_NOT_INCLUDED }); - valid = false + valid = false; } } - return valid + return valid; } function passesRateLimit(bidRequest) { const rateLimit = deepAccess(bidRequest, 'params.rateLimit', 1); if (!isNumber(rateLimit) || rateLimit > 1 || rateLimit < 0) { logError('AIDEM Bid Adapter: invalid rateLimit (must be a number between 0 and 1)', { bidder: BIDDER_CODE, code: ERROR_CODES.INVALID_RATELIMIT }); - return false + return false; } if (rateLimit !== 1) { - const randomRateValue = Math.random() + const randomRateValue = Math.random(); if (randomRateValue > rateLimit) { - return false + return false; } } - return true + return true; } function hasValidParameters(bidRequest) { // Assigned from AIDEM to a publisher website const siteId = deepAccess(bidRequest, 'params.siteId'); const publisherId = deepAccess(bidRequest, 'params.publisherId'); - const placementId = deepAccess(bidRequest, 'params.placementId'); if (!isStr(siteId)) { logError('AIDEM Bid Adapter: siteId must valid string', { bidder: BIDDER_CODE, code: ERROR_CODES.SITE_ID_INVALID_VALUE }); @@ -443,12 +442,7 @@ function hasValidParameters(bidRequest) { return false; } - if (!isStr(placementId)) { - logError('AIDEM Bid Adapter: placementId must valid string', { bidder: BIDDER_CODE, code: ERROR_CODES.PLACEMENT_ID_INVALID_VALUE }); - return false; - } - - return true + return true; } export const spec = { @@ -458,32 +452,32 @@ export const spec = { logInfo('bid: ', bidRequest); // check if request has valid mediaTypes - if (!hasValidMediaType(bidRequest)) return false + if (!hasValidMediaType(bidRequest)) return false; // check if request has valid media type parameters at adUnit level if (hasBannerMediaType(bidRequest) && !hasValidBannerMediaType(bidRequest)) { - return false + return false; } if (hasVideoMediaType(bidRequest) && !hasValidVideoMediaType(bidRequest)) { - return false + return false; } if (hasVideoMediaType(bidRequest) && !hasValidVideoParameters(bidRequest)) { - return false + return false; } if (!hasValidParameters(bidRequest)) { - return false + return false; } - return passesRateLimit(bidRequest) + return passesRateLimit(bidRequest); }, buildRequests: function(validBidRequests, bidderRequest) { logInfo('validBidRequests: ', validBidRequests); logInfo('bidderRequest: ', bidderRequest); - const prebidRequest = getPrebidRequestFields(bidderRequest, validBidRequests) + const prebidRequest = getPrebidRequestFields(bidderRequest, validBidRequests); const payloadString = JSON.stringify(prebidRequest); return { @@ -505,7 +499,7 @@ export const spec = { return; } logInfo('CPM OK'); - const bid = getPrebidResponseBidObject(bidObject) + const bid = getPrebidResponseBidObject(bidObject); bids.push(bid); }); return bids; @@ -514,14 +508,14 @@ export const spec = { onBidWon: function(bid) { // Bidder specific code logInfo('onBidWon bid: ', bid); - const notice = buildWinNotice(bid) + const notice = buildWinNotice(bid); ajax(endpoints.notice.win, null, JSON.stringify(notice), { method: 'POST', withCredentials: true }); }, onBidderError: function({ bidderRequest }) { // Bidder specific code - const notice = buildErrorNotice(bidderRequest) + const notice = buildErrorNotice(bidderRequest); ajax(endpoints.notice.error, null, JSON.stringify(notice), { method: 'POST', withCredentials: true }); }, -} +}; registerBidder(spec); diff --git a/modules/aidemBidAdapter.md b/modules/aidemBidAdapter.md index 76694f62f63..b59014c76ed 100644 --- a/modules/aidemBidAdapter.md +++ b/modules/aidemBidAdapter.md @@ -18,7 +18,7 @@ This module is GDPR and CCPA compliant, and no 3rd party userIds are allowed. |---------------|----------|-------------------------|------------|----------| | `siteId` | required | Unique site ID | `'ABCDEF'` | `String` | | `publisherId` | required | Unique publisher ID | `'ABCDEF'` | `String` | -| `placementId` | required | Unique publisher tag ID | `'ABCDEF'` | `String` | +| `placementId` | optional | Unique publisher tag ID | `'ABCDEF'` | `String` | | `rateLimit` | optional | Limit the volume sent to AIDEM. Must be between 0 and 1 | `0.6` | `Number` | @@ -68,7 +68,6 @@ var adUnits = [{ bids: [{ bidder: 'aidem', params: { - placementId: 'prebid-test-placementId', siteId: 'prebid-test-siteId', publisherId: 'prebid-test-publisherId', }, @@ -93,7 +92,6 @@ var adUnits = [{ bids: [{ bidder: 'aidem', params: { - placementId: 'prebid-test-placementId', siteId: 'prebid-test-siteId', publisherId: 'prebid-test-publisherId', }, diff --git a/test/spec/modules/aidemBidAdapter_spec.js b/test/spec/modules/aidemBidAdapter_spec.js index 2d7a8971c9c..f58e49eb364 100644 --- a/test/spec/modules/aidemBidAdapter_spec.js +++ b/test/spec/modules/aidemBidAdapter_spec.js @@ -59,18 +59,6 @@ const INVALID_BIDS = [ siteId: '3014912', } }, - { - bidder: 'aidem', - mediaTypes: { - banner: { - sizes: [[300, 250], [300, 600]], - } - }, - params: { - publisherId: '3014912', - siteId: '3014912', - } - }, { bidder: 'aidem', mediaTypes: { @@ -301,7 +289,7 @@ const WIN_NOTICE = { 'hb_size': '300x250', 'hb_source': 'client', 'hb_format': 'banner', - 'hb_adomain': 'tenutabene.it' + 'hb_adomain': 'example.com' }, 'auctionId': '85864730-6cbc-4e56-bc3c-a4a6596dca5b', From c0b91a2ea29bfc7f34f8359ad5dbcd749d8b63ce Mon Sep 17 00:00:00 2001 From: darkstar Date: Wed, 5 Apr 2023 11:51:43 +0200 Subject: [PATCH 13/21] Extended win notice --- modules/aidemBidAdapter.js | 5 ++ test/spec/modules/aidemBidAdapter_spec.js | 80 ++++++++++++++++++++--- 2 files changed, 77 insertions(+), 8 deletions(-) diff --git a/modules/aidemBidAdapter.js b/modules/aidemBidAdapter.js index e4d5c618b77..2f8732a8ec4 100644 --- a/modules/aidemBidAdapter.js +++ b/modules/aidemBidAdapter.js @@ -152,6 +152,7 @@ function getPageUrl(bidderRequest) { function buildWinNotice(bid) { const params = bid.params[0]; + const app = deepAccess(bid, 'meta.ext.app') return { publisherId: params.publisherId, siteId: params.siteId, @@ -167,6 +168,9 @@ function buildWinNotice(bid) { ttl: bid.ttl, requestTimestamp: bid.requestTimestamp, responseTimestamp: bid.responseTimestamp, + mediatype: bid.mediaType, + environment: app ? 'app' : 'web', + ...app }; } @@ -348,6 +352,7 @@ function getPrebidResponseBidObject(openRTBResponseBidObject) { function setPrebidResponseBidObjectMeta(prebidResponseBidObject, openRTBResponseBidObject) { logInfo('AIDEM Bid Adapter meta', openRTBResponseBidObject); deepSetValue(prebidResponseBidObject, 'meta.advertiserDomains', deepAccess(openRTBResponseBidObject, 'meta.advertiserDomains')); + deepSetValue(prebidResponseBidObject, 'meta.ext', deepAccess(openRTBResponseBidObject, 'meta.ext')); if (openRTBResponseBidObject.cat && Array.isArray(openRTBResponseBidObject.cat)) { const primaryCatId = openRTBResponseBidObject.cat.shift(); deepSetValue(prebidResponseBidObject, 'meta.primaryCatId', primaryCatId); diff --git a/test/spec/modules/aidemBidAdapter_spec.js b/test/spec/modules/aidemBidAdapter_spec.js index f58e49eb364..6a875feb2a9 100644 --- a/test/spec/modules/aidemBidAdapter_spec.js +++ b/test/spec/modules/aidemBidAdapter_spec.js @@ -276,7 +276,7 @@ const SERVER_RESPONSE_VIDEO = { }, } -const WIN_NOTICE = { +const WIN_NOTICE_WEB = { 'adId': '3a20ee5dc78c1e', 'adUnitCode': 'div-gpt-ad-1460505748561-0', 'creativeId': '24277955', @@ -297,9 +297,71 @@ const WIN_NOTICE = { 'USD' ], 'mediaType': 'banner', - 'advertiserDomains': [ - 'abc.com' + 'meta': { + 'advertiserDomains': [ + 'cloudflare.com' + ], + 'ext': {} + }, + 'size': '300x250', + 'params': [ + { + 'placementId': '13144370', + 'siteId': '23434', + 'publisherId': '7689670753' + } + ], + 'width': 300, + 'height': 250, + 'status': 'rendered', + 'transactionId': 'ce089116-4251-45c3-bdbb-3a03cb13816b', + 'ttl': 300, + 'requestTimestamp': 1666796241007, + 'responseTimestamp': 1666796241021, + metrics: { + getMetrics() { + return { + + } + } + } +} + +const WIN_NOTICE_APP = { + 'adId': '3a20ee5dc78c1e', + 'adUnitCode': 'div-gpt-ad-1460505748561-0', + 'creativeId': '24277955', + 'cpm': 1, + 'netRevenue': false, + 'adserverTargeting': { + 'hb_bidder': 'aidem', + 'hb_adid': '3a20ee5dc78c1e', + 'hb_pb': '1.00', + 'hb_size': '300x250', + 'hb_source': 'client', + 'hb_format': 'banner', + 'hb_adomain': 'example.com' + }, + + 'auctionId': '85864730-6cbc-4e56-bc3c-a4a6596dca5b', + 'currency': [ + 'USD' ], + 'mediaType': 'banner', + 'meta': { + 'advertiserDomains': [ + 'cloudflare.com' + ], + 'ext': { + 'app': { + 'app_bundle': '{{APP_BUNDLE}}', + 'app_id': '{{APP_ID}}', + 'app_name': '{{APP_NAME}}', + 'app_store_url': '{{APP_STORE_URL}}', + 'inventory_source': '{{INVENTORY_SOURCE}}' + } + } + }, 'size': '300x250', 'params': [ { @@ -549,11 +611,13 @@ describe('Aidem adapter', () => { expect(spec.onBidWon).to.exist.and.to.be.a('function') }); - it(`should send a valid bid won notice`, function () { - spec.onBidWon(WIN_NOTICE); - // server.respondWith('POST', WIN_EVENT_URL, [ - // 400, {'Content-Type': 'application/json'}, ) - // ]); + it(`should send a valid bid won notice from web environment`, function () { + spec.onBidWon(WIN_NOTICE_WEB); + expect(server.requests.length).to.equal(1); + }); + + it(`should send a valid bid won notice from app environment`, function () { + spec.onBidWon(WIN_NOTICE_APP); expect(server.requests.length).to.equal(1); }); }); From 2414a0b11bfef43e93f54228474451f882c676ff Mon Sep 17 00:00:00 2001 From: darkstar Date: Fri, 5 May 2023 16:46:58 +0200 Subject: [PATCH 14/21] Added arbitrary ext field to win notice --- modules/aidemBidAdapter.js | 4 +++- test/spec/modules/aidemBidAdapter_spec.js | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/modules/aidemBidAdapter.js b/modules/aidemBidAdapter.js index 2f8732a8ec4..d43c07aeece 100644 --- a/modules/aidemBidAdapter.js +++ b/modules/aidemBidAdapter.js @@ -153,6 +153,7 @@ function getPageUrl(bidderRequest) { function buildWinNotice(bid) { const params = bid.params[0]; const app = deepAccess(bid, 'meta.ext.app') + const winNoticeExt = deepAccess(bid, 'meta.ext.win_notice_ext') return { publisherId: params.publisherId, siteId: params.siteId, @@ -170,7 +171,8 @@ function buildWinNotice(bid) { responseTimestamp: bid.responseTimestamp, mediatype: bid.mediaType, environment: app ? 'app' : 'web', - ...app + ...app, + ext: winNoticeExt, }; } diff --git a/test/spec/modules/aidemBidAdapter_spec.js b/test/spec/modules/aidemBidAdapter_spec.js index 6a875feb2a9..8268efde2a1 100644 --- a/test/spec/modules/aidemBidAdapter_spec.js +++ b/test/spec/modules/aidemBidAdapter_spec.js @@ -359,6 +359,9 @@ const WIN_NOTICE_APP = { 'app_name': '{{APP_NAME}}', 'app_store_url': '{{APP_STORE_URL}}', 'inventory_source': '{{INVENTORY_SOURCE}}' + }, + 'win_notice_ext': { + 'seatid': '{{SEAT_ID}}' } } }, From d24ceda030e0ea737ad19d9fdbdaca1494f9dc00 Mon Sep 17 00:00:00 2001 From: darkstar Date: Thu, 24 Aug 2023 17:44:10 +0200 Subject: [PATCH 15/21] Moved aidemBidAdapter implementation to comply with ortbConverter --- modules/aidemBidAdapter.js | 371 +++-------------- test/spec/modules/aidemBidAdapter_spec.js | 462 +++++++--------------- 2 files changed, 210 insertions(+), 623 deletions(-) diff --git a/modules/aidemBidAdapter.js b/modules/aidemBidAdapter.js index 7469f26156b..c6a5cd96fb6 100644 --- a/modules/aidemBidAdapter.js +++ b/modules/aidemBidAdapter.js @@ -1,27 +1,15 @@ -import { - _each, - contains, - deepAccess, - deepSetValue, - getDNT, - isBoolean, - isNumber, - isStr, - logError, - logInfo -} from '../src/utils.js'; +import {deepAccess, deepSetValue, isBoolean, isNumber, isStr, logError, logInfo} from '../src/utils.js'; import {config} from '../src/config.js'; import {BANNER, VIDEO} from '../src/mediaTypes.js'; import {registerBidder} from '../src/adapters/bidderFactory.js'; import {getRefererInfo} from '../src/refererDetection.js'; import {ajax} from '../src/ajax.js'; +import {ortbConverter} from '../libraries/ortbConverter/converter.js'; const BIDDER_CODE = 'aidem'; const BASE_URL = 'https://zero.aidemsrv.com'; const LOCAL_BASE_URL = 'http://127.0.0.1:8787'; -const AVAILABLE_CURRENCIES = ['USD']; -const DEFAULT_CURRENCY = ['USD']; // NOTE - USD is the only supported currency right now; Hardcoded for bids const SUPPORTED_MEDIA_TYPES = [BANNER, VIDEO]; const REQUIRED_VIDEO_PARAMS = [ 'mimes', 'protocols', 'context' ]; @@ -37,34 +25,63 @@ export const ERROR_CODES = { }; const endpoints = { - request: `${BASE_URL}/bid/request`, - notice: { - win: `${BASE_URL}/notice/win`, - timeout: `${BASE_URL}/notice/timeout`, - error: `${BASE_URL}/notice/error`, - } + request: `${BASE_URL}/prebidjs/ortb/v2.6/bid/request`, + // notice: { + // win: `${BASE_URL}/notice/win`, + // timeout: `${BASE_URL}/notice/timeout`, + // error: `${BASE_URL}/notice/error`, + // } }; -export function setEndPoints(env = null, path = '', mediaType = BANNER) { +export function setEndPoints(env = null, path = '') { switch (env) { case 'local': - endpoints.request = mediaType === BANNER ? `${LOCAL_BASE_URL}${path}/bid/request` : `${LOCAL_BASE_URL}${path}/bid/videorequest`; - endpoints.notice.win = `${LOCAL_BASE_URL}${path}/notice/win`; - endpoints.notice.error = `${LOCAL_BASE_URL}${path}/notice/error`; - endpoints.notice.timeout = `${LOCAL_BASE_URL}${path}/notice/timeout`; + endpoints.request = `${LOCAL_BASE_URL}${path}/prebidjs/ortb/v2.6/bid/request`; break; case 'main': - endpoints.request = mediaType === BANNER ? `${BASE_URL}${path}/bid/request` : `${BASE_URL}${path}/bid/videorequest`; - endpoints.notice.win = `${BASE_URL}${path}/notice/win`; - endpoints.notice.error = `${BASE_URL}${path}/notice/error`; - endpoints.notice.timeout = `${BASE_URL}${path}/notice/timeout`; + endpoints.request = `${BASE_URL}${path}/prebidjs/ortb/v2.6/bid/request`; break; } return endpoints; } config.getConfig('aidem', function (config) { - if (config.aidem.env) { setEndPoints(config.aidem.env, config.aidem.path, config.aidem.mediaType); } + if (config.aidem.env) { setEndPoints(config.aidem.env, config.aidem.path); } +}); + +const converter = ortbConverter({ + context: { + netRevenue: true, + ttl: 30 + }, + request(buildRequest, imps, bidderRequest, context) { + logInfo('Building request'); + const request = buildRequest(imps, bidderRequest, context); + deepSetValue(request, 'at', 1); + setPrebidRequestEnvironment(request); + deepSetValue(request, 'regs', getRegs()); + deepSetValue(request, 'site.publisher.id', bidderRequest.bids[0].params.publisherId); + deepSetValue(request, 'site.id', bidderRequest.bids[0].params.siteId); + return request; + }, + imp(buildImp, bidRequest, context) { + logInfo('Building imp bidRequest', bidRequest); + const imp = buildImp(bidRequest, context); + deepSetValue(imp, 'tagId', bidRequest.params.placementId); + return imp; + }, + bidResponse(buildBidResponse, bid, context) { + const {bidRequest} = context; + const bidResponse = buildBidResponse(bid, context); + logInfo('Building bidResponse'); + logInfo('bid', bid); + logInfo('bidRequest', bidRequest); + logInfo('bidResponse', bidResponse); + if (bidResponse.mediaType === VIDEO) { + deepSetValue(bidResponse, 'vastUrl', bid.adm); + } + return bidResponse; + } }); // AIDEM Custom FN @@ -89,49 +106,6 @@ function recur(obj) { return result; } -// ================================================================================= -function getConnectionType() { - const connection = navigator.connection || navigator.webkitConnection; - if (!connection) { - return 0; - } - switch (connection.type) { - case 'ethernet': - return 1; - case 'wifi': - return 2; - case 'cellular': - switch (connection.effectiveType) { - case 'slow-2g': - return 4; - case '2g': - return 4; - case '3g': - return 5; - case '4g': - return 6; - case '5g': - return 7; - default: - return 3; - } - default: - return 0; - } -} - -function getDevice() { - const language = navigator.language || navigator.browserLanguage || navigator.userLanguage || navigator.systemLanguage; - return { - ua: navigator.userAgent, - dnt: !!getDNT(), - language: language, - connectiontype: getConnectionType(), - screen_width: screen.width, - screen_height: screen.height - }; -} - function getRegs() { let regs = {}; const consentManagement = config.getConfig('consentManagement'); @@ -157,129 +131,6 @@ function getRegs() { return regs; } -function getPageUrl(bidderRequest) { - return bidderRequest?.refererInfo?.page; -} - -function buildWinNotice(bid) { - const params = bid.params[0]; - const app = deepAccess(bid, 'meta.ext.app') - const winNoticeExt = deepAccess(bid, 'meta.ext.win_notice_ext') - return { - publisherId: params.publisherId, - siteId: params.siteId, - placementId: params.placementId, - burl: deepAccess(bid, 'meta.burl'), - cpm: bid.cpm, - currency: bid.currency, - impid: deepAccess(bid, 'meta.impid'), - dsp_id: deepAccess(bid, 'meta.dsp_id'), - adUnitCode: bid.adUnitCode, - // TODO: fix auctionId/transactionId leak: https://github.com/prebid/Prebid.js/issues/9781 - auctionId: bid.auctionId, - transactionId: bid.transactionId, - ttl: bid.ttl, - requestTimestamp: bid.requestTimestamp, - responseTimestamp: bid.responseTimestamp, - mediatype: bid.mediaType, - environment: app ? 'app' : 'web', - ...app, - ext: winNoticeExt, - }; -} - -function buildErrorNotice(prebidErrorResponse) { - return { - message: `Prebid.js: Server call for ${prebidErrorResponse.bidderCode} failed.`, - url: encodeURIComponent(getPageUrl(prebidErrorResponse)), - auctionId: prebidErrorResponse.auctionId, - bidderRequestId: prebidErrorResponse.bidderRequestId, - metrics: {} - }; -} - -function hasValidFloor(obj) { - if (!obj) return false; - const hasValue = !isNaN(Number(obj.value)); - const hasCurrency = contains(AVAILABLE_CURRENCIES, obj.currency); - return hasValue && hasCurrency; -} - -function getMediaType(bidRequest) { - if ((bidRequest.mediaTypes && bidRequest.mediaTypes.hasOwnProperty('video')) || bidRequest.params.hasOwnProperty('video')) { return VIDEO; } - return BANNER; -} - -function getPrebidRequestFields(bidderRequest, bidRequests) { - const payload = {}; - // Base Payload Data - deepSetValue(payload, 'id', bidderRequest.bidderRequestId); - // Impressions - setPrebidImpressionObject(bidRequests, payload); - // Device - deepSetValue(payload, 'device', getDevice()); - // Timeout - deepSetValue(payload, 'tmax', bidderRequest.timeout); - // Currency - deepSetValue(payload, 'cur', DEFAULT_CURRENCY); - // Timezone - deepSetValue(payload, 'tz', new Date().getTimezoneOffset()); - // Privacy Regs - deepSetValue(payload, 'regs', getRegs()); - // Site - setPrebidSiteObject(bidderRequest, payload); - // Environment - setPrebidRequestEnvironment(payload); - // AT auction type - deepSetValue(payload, 'at', 1); - - return payload; -} - -function setPrebidImpressionObject(bidRequests, payload) { - payload.imp = []; - _each(bidRequests, function (bidRequest) { - const impressionObject = {}; - // Placement or ad tag used to initiate the auction - deepSetValue(impressionObject, 'id', bidRequest.bidId); - // Transaction id - // TODO: `imp.tid` is not ORTB, is this intentional? - deepSetValue(impressionObject, 'tid', deepAccess(bidRequest, 'ortb2Imp.ext.tid')); - // placement id - deepSetValue(impressionObject, 'tagid', deepAccess(bidRequest, 'params.placementId', null)); - // Publisher id - deepSetValue(payload, 'site.publisher.id', deepAccess(bidRequest, 'params.publisherId')); - // Site id - deepSetValue(payload, 'site.id', deepAccess(bidRequest, 'params.siteId')); - const mediaType = getMediaType(bidRequest); - switch (mediaType) { - case 'banner': - setPrebidImpressionObjectBanner(bidRequest, impressionObject); - break; - case 'video': - setPrebidImpressionObjectVideo(bidRequest, impressionObject); - break; - } - - // Floor (optional) - setPrebidImpressionObjectFloor(bidRequest, impressionObject); - - impressionObject.imp_ext = {}; - - payload.imp.push(impressionObject); - }); -} - -function setPrebidSiteObject(bidderRequest, payload) { - deepSetValue(payload, 'site.domain', deepAccess(bidderRequest, 'refererInfo.domain')); - deepSetValue(payload, 'site.page', deepAccess(bidderRequest, 'refererInfo.page')); - deepSetValue(payload, 'site.referer', deepAccess(bidderRequest, 'refererInfo.ref')); - deepSetValue(payload, 'site.cat', deepAccess(bidderRequest, 'ortb2.site.cat')); - deepSetValue(payload, 'site.sectioncat', deepAccess(bidderRequest, 'ortb2.site.sectioncat')); - deepSetValue(payload, 'site.keywords', deepAccess(bidderRequest, 'ortb2.site.keywords')); - deepSetValue(payload, 'site.site_ext', deepAccess(bidderRequest, 'ortb2.site.ext')); // see https://docs.prebid.org/features/firstPartyData.html -} - function setPrebidRequestEnvironment(payload) { const __navigator = JSON.parse(JSON.stringify(recur(navigator))); delete __navigator.plugins; @@ -296,92 +147,6 @@ function setPrebidRequestEnvironment(payload) { deepSetValue(payload, 'environment.wpar.innerHeight', window.innerHeight); } -function setPrebidImpressionObjectFloor(bidRequest, impressionObject) { - const floor = deepAccess(bidRequest, 'params.floor'); - if (hasValidFloor(floor)) { - deepSetValue(impressionObject, 'floor.value', floor.value); - deepSetValue(impressionObject, 'floor.currency', floor.currency); - } -} - -function setPrebidImpressionObjectBanner(bidRequest, impressionObject) { - deepSetValue(impressionObject, 'mediatype', BANNER); - deepSetValue(impressionObject, 'banner.topframe', 1); - deepSetValue(impressionObject, 'banner.format', []); - _each(bidRequest.mediaTypes.banner.sizes, function (bannerFormat) { - const format = {}; - deepSetValue(format, 'w', bannerFormat[0]); - deepSetValue(format, 'h', bannerFormat[1]); - deepSetValue(format, 'format_ext', {}); - impressionObject.banner.format.push(format); - }); -} - -function setPrebidImpressionObjectVideo(bidRequest, impressionObject) { - deepSetValue(impressionObject, 'mediatype', VIDEO); - deepSetValue(impressionObject, 'video.format', []); - deepSetValue(impressionObject, 'video.mimes', bidRequest.mediaTypes.video.mimes); - deepSetValue(impressionObject, 'video.minDuration', bidRequest.mediaTypes.video.minduration); - deepSetValue(impressionObject, 'video.maxDuration', bidRequest.mediaTypes.video.maxduration); - deepSetValue(impressionObject, 'video.protocols', bidRequest.mediaTypes.video.protocols); - deepSetValue(impressionObject, 'video.context', bidRequest.mediaTypes.video.context); - deepSetValue(impressionObject, 'video.playbackmethod', bidRequest.mediaTypes.video.playbackmethod); - deepSetValue(impressionObject, 'skip', bidRequest.mediaTypes.video.skip); - deepSetValue(impressionObject, 'skipafter', bidRequest.mediaTypes.video.skipafter); - deepSetValue(impressionObject, 'video.pos', bidRequest.mediaTypes.video.pos); - _each(bidRequest.mediaTypes.video.playerSize, function (videoPlayerSize) { - const format = {}; - deepSetValue(format, 'w', videoPlayerSize[0]); - deepSetValue(format, 'h', videoPlayerSize[1]); - deepSetValue(format, 'format_ext', {}); - impressionObject.video.format.push(format); - }); -} - -function getPrebidResponseBidObject(openRTBResponseBidObject) { - const prebidResponseBidObject = {}; - // Common properties - deepSetValue(prebidResponseBidObject, 'requestId', openRTBResponseBidObject.impid); - deepSetValue(prebidResponseBidObject, 'cpm', parseFloat(openRTBResponseBidObject.price)); - deepSetValue(prebidResponseBidObject, 'creativeId', openRTBResponseBidObject.crid); - deepSetValue(prebidResponseBidObject, 'currency', openRTBResponseBidObject.cur ? openRTBResponseBidObject.cur.toUpperCase() : DEFAULT_CURRENCY); - deepSetValue(prebidResponseBidObject, 'width', openRTBResponseBidObject.w); - deepSetValue(prebidResponseBidObject, 'height', openRTBResponseBidObject.h); - deepSetValue(prebidResponseBidObject, 'dealId', openRTBResponseBidObject.dealid); - deepSetValue(prebidResponseBidObject, 'netRevenue', true); - deepSetValue(prebidResponseBidObject, 'ttl', 60000); - - if (openRTBResponseBidObject.mediatype === VIDEO) { - logInfo('bidObject.mediatype == VIDEO'); - deepSetValue(prebidResponseBidObject, 'mediaType', VIDEO); - deepSetValue(prebidResponseBidObject, 'vastUrl', openRTBResponseBidObject.adm); - } else { - logInfo('bidObject.mediatype == BANNER'); - deepSetValue(prebidResponseBidObject, 'mediaType', BANNER); - deepSetValue(prebidResponseBidObject, 'ad', openRTBResponseBidObject.adm); - } - setPrebidResponseBidObjectMeta(prebidResponseBidObject, openRTBResponseBidObject); - return prebidResponseBidObject; -} - -function setPrebidResponseBidObjectMeta(prebidResponseBidObject, openRTBResponseBidObject) { - logInfo('AIDEM Bid Adapter meta', openRTBResponseBidObject); - deepSetValue(prebidResponseBidObject, 'meta.advertiserDomains', deepAccess(openRTBResponseBidObject, 'meta.advertiserDomains')); - deepSetValue(prebidResponseBidObject, 'meta.ext', deepAccess(openRTBResponseBidObject, 'meta.ext')); - if (openRTBResponseBidObject.cat && Array.isArray(openRTBResponseBidObject.cat)) { - const primaryCatId = openRTBResponseBidObject.cat.shift(); - deepSetValue(prebidResponseBidObject, 'meta.primaryCatId', primaryCatId); - deepSetValue(prebidResponseBidObject, 'meta.secondaryCatIds', openRTBResponseBidObject.cat); - } - deepSetValue(prebidResponseBidObject, 'meta.id', openRTBResponseBidObject.id); - deepSetValue(prebidResponseBidObject, 'meta.dsp_id', openRTBResponseBidObject.dsp_id); - deepSetValue(prebidResponseBidObject, 'meta.adid', openRTBResponseBidObject.adid); - deepSetValue(prebidResponseBidObject, 'meta.burl', openRTBResponseBidObject.burl); - deepSetValue(prebidResponseBidObject, 'meta.impid', openRTBResponseBidObject.impid); - deepSetValue(prebidResponseBidObject, 'meta.cat', openRTBResponseBidObject.cat); - deepSetValue(prebidResponseBidObject, 'meta.cid', openRTBResponseBidObject.cid); -} - function hasValidMediaType(bidRequest) { const supported = hasBannerMediaType(bidRequest) || hasVideoMediaType(bidRequest); if (!supported) { @@ -494,48 +259,38 @@ export const spec = { return passesRateLimit(bidRequest); }, - buildRequests: function(validBidRequests, bidderRequest) { - logInfo('validBidRequests: ', validBidRequests); + buildRequests: function(bidRequests, bidderRequest) { + logInfo('bidRequests: ', bidRequests); logInfo('bidderRequest: ', bidderRequest); - const prebidRequest = getPrebidRequestFields(bidderRequest, validBidRequests); - const payloadString = JSON.stringify(prebidRequest); - + const data = converter.toORTB({bidRequests, bidderRequest}); + logInfo('request payload', data); return { method: 'POST', url: endpoints.request, - data: payloadString, + data, options: { withCredentials: true } }; }, - interpretResponse: function (serverResponse) { - const bids = []; - logInfo('serverResponse: ', serverResponse); - _each(serverResponse.body.bid, function (bidObject) { - logInfo('bidObject: ', bidObject); - if (!bidObject.price || !bidObject.adm) { - return; - } - logInfo('CPM OK'); - const bid = getPrebidResponseBidObject(bidObject); - bids.push(bid); - }); - return bids; + interpretResponse: function (serverResponse, request) { + logInfo('serverResponse body: ', serverResponse.body); + logInfo('request data: ', request.data); + const ortbBids = converter.fromORTB({response: serverResponse.body, request: request.data}).bids; + logInfo('ortbBids: ', ortbBids); + return ortbBids; }, onBidWon: function(bid) { // Bidder specific code logInfo('onBidWon bid: ', bid); - const notice = buildWinNotice(bid); - ajax(endpoints.notice.win, null, JSON.stringify(notice), { method: 'POST', withCredentials: true }); + ajax(bid.burl); }, - onBidderError: function({ bidderRequest }) { - // Bidder specific code - const notice = buildErrorNotice(bidderRequest); - ajax(endpoints.notice.error, null, JSON.stringify(notice), { method: 'POST', withCredentials: true }); - }, + // onBidderError: function({ bidderRequest }) { + // const notice = buildErrorNotice(bidderRequest); + // ajax(endpoints.notice.error, null, JSON.stringify(notice), { method: 'POST', withCredentials: true }); + // }, }; registerBidder(spec); diff --git a/test/spec/modules/aidemBidAdapter_spec.js b/test/spec/modules/aidemBidAdapter_spec.js index 8b401491ba0..14b21a53412 100644 --- a/test/spec/modules/aidemBidAdapter_spec.js +++ b/test/spec/modules/aidemBidAdapter_spec.js @@ -5,6 +5,7 @@ import {deepSetValue} from '../../../src/utils'; import {server} from '../../mocks/xhr'; import {config} from '../../../src/config'; import {NATIVE} from '../../../src/mediaTypes.js'; +import {CONVERTER} from '../../../modules/improvedigitalBidAdapter'; // Full banner + Full Video + Basic Banner + Basic Video const VALID_BIDS = [ @@ -155,9 +156,9 @@ const DEFAULT_VALID_BANNER_REQUESTS = [ { adUnitCode: 'test-div', auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', - bidId: '22c4871113f461', + bidId: '2705bfae8ea667', bidder: 'aidem', - bidderRequestId: '15246a574e859f', + bidderRequestId: '1bbb7854dfa0d8', mediaTypes: { banner: { sizes: [ @@ -171,11 +172,7 @@ const DEFAULT_VALID_BANNER_REQUESTS = [ placementId: '13144370' }, src: 'client', - ortb2Imp: { - ext: { - tid: '54a58774-7a41-494e-9aaf-fa7b79164f0c', - }, - }, + transactionId: 'db739693-9b4a-4669-9945-8eab938783cc' } ]; @@ -183,9 +180,9 @@ const DEFAULT_VALID_VIDEO_REQUESTS = [ { adUnitCode: 'test-div', auctionId: 'b06c5141-fe8f-4cdf-9d7d-54415490a917', - bidId: '22c4871113f461', + bidId: '2705bfae8ea667', bidder: 'aidem', - bidderRequestId: '15246a574e859f', + bidderRequestId: '1bbb7854dfa0d8', mediaTypes: { video: { minduration: 7, @@ -200,18 +197,23 @@ const DEFAULT_VALID_VIDEO_REQUESTS = [ placementId: '13144370' }, src: 'client', - ortb2Imp: { - ext: { - tid: '54a58774-7a41-494e-9aaf-fa7b79164f0c', - } - }, + transactionId: 'db739693-9b4a-4669-9945-8eab938783cc' } ]; const VALID_BIDDER_REQUEST = { - auctionId: '6e9b46c3-65a8-46ea-89f4-c5071110c85c', + auctionId: '19c97f22-5bd1-4b16-a128-80f75fb0a8a0', bidderCode: 'aidem', - bidderRequestId: '170ea5d2b1d073', + bidderRequestId: '1bbb7854dfa0d8', + bids: [ + { + params: { + placementId: '13144370', + siteId: '23434', + publisherId: '7689670753' + }, + } + ], refererInfo: { page: 'test-page', domain: 'test-domain', @@ -219,182 +221,68 @@ const VALID_BIDDER_REQUEST = { }, } -// Add mediatype const SERVER_RESPONSE_BANNER = { - body: { - id: 'efa1930a-bc3e-4fd0-8368-08bc40236b4f', - bid: [ - // BANNER - { - 'id': '2e614be960ee1d', - 'impid': '2e614be960ee1d', - 'price': 7.91, - 'mediatype': 'banner', - 'adid': '24277955', - 'adm': 'creativity_banner', - 'adomain': [ - 'aidem.com' - ], - 'iurl': 'http://www.aidem.com', - 'cat': [], - 'cid': '4193561', - 'crid': '24277955', - 'w': 300, - 'h': 250, - 'ext': { - 'dspid': 85, - 'advbrandid': 1246, - 'advbrand': 'AIDEM' - } - }, - ], - cur: 'USD' - }, -} - -const SERVER_RESPONSE_VIDEO = { - body: { - id: 'efa1930a-bc3e-4fd0-8368-08bc40236b4f', - bid: [ - // VIDEO - { - 'id': '2876a29392a47c', - 'impid': '2876a29392a47c', - 'price': 7.93, - 'mediatype': 'video', - 'adid': '24277955', - 'adm': 'https://hermes.aidemsrv.com/vast-tag/cl9mzhhd502uq09l720uegb02?auction_id={{AUCTION_ID}}&cachebuster={{CACHEBUSTER}}', - 'adomain': [ - 'aidem.com' - ], - 'iurl': 'http://www.aidem.com', - 'cat': [], - 'cid': '4193561', - 'crid': '24277955', - 'w': 640, - 'h': 480, - 'ext': { - 'dspid': 85, - 'advbrandid': 1246, - 'advbrand': 'AIDEM' - } - } - ], - cur: 'USD' - }, -} - -const WIN_NOTICE_WEB = { - 'adId': '3a20ee5dc78c1e', - 'adUnitCode': 'div-gpt-ad-1460505748561-0', - 'creativeId': '24277955', - 'cpm': 1, - 'netRevenue': false, - 'adserverTargeting': { - 'hb_bidder': 'aidem', - 'hb_adid': '3a20ee5dc78c1e', - 'hb_pb': '1.00', - 'hb_size': '300x250', - 'hb_source': 'client', - 'hb_format': 'banner', - 'hb_adomain': 'example.com' - }, - - 'auctionId': '85864730-6cbc-4e56-bc3c-a4a6596dca5b', - 'currency': [ - 'USD' - ], - 'mediaType': 'banner', - 'meta': { - 'advertiserDomains': [ - 'cloudflare.com' - ], - 'ext': {} - }, - 'size': '300x250', - 'params': [ + 'id': '19c97f22-5bd1-4b16-a128-80f75fb0a8a0', + 'seatbid': [ { - 'placementId': '13144370', - 'siteId': '23434', - 'publisherId': '7689670753' + 'bid': [ + { + 'id': 'beeswax/aidem', + 'impid': '2705bfae8ea667', + 'price': 0.00875, + 'burl': 'imp_burl', + 'adm': 'creativity_banner', + 'adid': '2:64:162:1001', + 'adomain': [ + 'aidem.com' + ], + 'cid': '64', + 'crid': 'aidem-1001', + 'cat': [], + 'w': 300, + 'h': 250, + 'mtype': 1 + } + ], + 'seat': 'aidemdsp', + 'group': 0 } ], - 'width': 300, - 'height': 250, - 'status': 'rendered', - 'transactionId': 'ce089116-4251-45c3-bdbb-3a03cb13816b', - 'ttl': 300, - 'requestTimestamp': 1666796241007, - 'responseTimestamp': 1666796241021, - metrics: { - getMetrics() { - return { - - } - } - } + 'cur': 'USD' } -const WIN_NOTICE_APP = { - 'adId': '3a20ee5dc78c1e', - 'adUnitCode': 'div-gpt-ad-1460505748561-0', - 'creativeId': '24277955', - 'cpm': 1, - 'netRevenue': false, - 'adserverTargeting': { - 'hb_bidder': 'aidem', - 'hb_adid': '3a20ee5dc78c1e', - 'hb_pb': '1.00', - 'hb_size': '300x250', - 'hb_source': 'client', - 'hb_format': 'banner', - 'hb_adomain': 'example.com' - }, - - 'auctionId': '85864730-6cbc-4e56-bc3c-a4a6596dca5b', - 'currency': [ - 'USD' - ], - 'mediaType': 'banner', - 'meta': { - 'advertiserDomains': [ - 'cloudflare.com' - ], - 'ext': { - 'app': { - 'app_bundle': '{{APP_BUNDLE}}', - 'app_id': '{{APP_ID}}', - 'app_name': '{{APP_NAME}}', - 'app_store_url': '{{APP_STORE_URL}}', - 'inventory_source': '{{INVENTORY_SOURCE}}' - }, - 'win_notice_ext': { - 'seatid': '{{SEAT_ID}}' - } - } - }, - 'size': '300x250', - 'params': [ +const SERVER_RESPONSE_VIDEO = { + 'id': '19c97f22-5bd1-4b16-a128-80f75fb0a8a0', + 'seatbid': [ { - 'placementId': '13144370', - 'siteId': '23434', - 'publisherId': '7689670753' + 'bid': [ + { + 'id': 'beeswax/aidem', + 'impid': '2705bfae8ea667', + 'price': 0.00875, + 'burl': 'imp_burl', + 'adm': 'creativity_banner', + 'adid': '2:64:162:1001', + 'adomain': [ + 'aidem.com' + ], + 'cid': '64', + 'crid': 'aidem-1001', + 'cat': [], + 'w': 300, + 'h': 250, + 'mtype': 2 + } + ], + 'seat': 'aidemdsp', + 'group': 0 } ], - 'width': 300, - 'height': 250, - 'status': 'rendered', - 'transactionId': 'ce089116-4251-45c3-bdbb-3a03cb13816b', - 'ttl': 300, - 'requestTimestamp': 1666796241007, - 'responseTimestamp': 1666796241021, - metrics: { - getMetrics() { - return { + 'cur': 'USD' +} - } - } - } +const WIN_NOTICE = { + burl: 'burl' } const ERROR_NOTICE = { @@ -512,109 +400,91 @@ describe('Aidem adapter', () => { const requests = spec.buildRequests(DEFAULT_VALID_BANNER_REQUESTS, VALID_BIDDER_REQUEST); expect(requests).to.be.an('object'); expect(requests.method).to.be.a('string') - expect(requests.data).to.be.a('string') + expect(requests.data).to.be.a('object') expect(requests.options).to.be.an('object').that.have.a.property('withCredentials') }); it('should have a well formatted banner payload', () => { - const requests = spec.buildRequests(DEFAULT_VALID_BANNER_REQUESTS, VALID_BIDDER_REQUEST); - const payload = JSON.parse(requests.data) - expect(payload).to.be.a('object').that.has.all.keys( - 'id', 'imp', 'device', 'cur', 'tz', 'regs', 'site', 'environment', 'at' + const {data} = spec.buildRequests(DEFAULT_VALID_BANNER_REQUESTS, VALID_BIDDER_REQUEST); + expect(data).to.be.a('object').that.has.all.keys( + 'id', 'imp', 'regs', 'site', 'environment', 'at', 'test' ) - expect(payload.imp).to.be.a('array').that.has.lengthOf(DEFAULT_VALID_BANNER_REQUESTS.length) + expect(data.imp).to.be.a('array').that.has.lengthOf(DEFAULT_VALID_BANNER_REQUESTS.length) - expect(payload.imp[0]).to.be.a('object').that.has.all.keys( - 'banner', 'id', 'mediatype', 'imp_ext', 'tid', 'tagid' + expect(data.imp[0]).to.be.a('object').that.has.all.keys( + 'banner', 'id', 'tagId' ) - expect(payload.imp[0].banner).to.be.a('object').that.has.all.keys( + expect(data.imp[0].banner).to.be.a('object').that.has.all.keys( 'format', 'topframe' ) }); it('should have a well formatted video payload', () => { - const requests = spec.buildRequests(DEFAULT_VALID_VIDEO_REQUESTS, VALID_BIDDER_REQUEST); - const payload = JSON.parse(requests.data) - expect(payload).to.be.a('object').that.has.all.keys( - 'id', 'imp', 'device', 'cur', 'tz', 'regs', 'site', 'environment', 'at' + const {data} = spec.buildRequests(DEFAULT_VALID_VIDEO_REQUESTS, VALID_BIDDER_REQUEST); + expect(data).to.be.a('object').that.has.all.keys( + 'id', 'imp', 'regs', 'site', 'environment', 'at', 'test' ) - expect(payload.imp).to.be.a('array').that.has.lengthOf(DEFAULT_VALID_VIDEO_REQUESTS.length) + expect(data.imp).to.be.a('array').that.has.lengthOf(DEFAULT_VALID_VIDEO_REQUESTS.length) - expect(payload.imp[0]).to.be.a('object').that.has.all.keys( - 'video', 'id', 'mediatype', 'imp_ext', 'tid', 'tagid' + expect(data.imp[0]).to.be.a('object').that.has.all.keys( + 'video', 'id', 'tagId' ) - expect(payload.imp[0].video).to.be.a('object').that.has.all.keys( - 'format', 'mimes', 'minDuration', 'maxDuration', 'protocols' - ) - }); - - it('should have a well formatted bid floor payload if configured', () => { - const validBannerRequests = utils.deepClone(DEFAULT_VALID_BANNER_REQUESTS) - validBannerRequests[0].params.floor = { - value: 1.98, - currency: 'USD' - } - const requests = spec.buildRequests(validBannerRequests, VALID_BIDDER_REQUEST); - const payload = JSON.parse(requests.data) - const { floor } = payload.imp[0] - expect(floor).to.be.a('object').that.has.all.keys( - 'value', 'currency' + expect(data.imp[0].video).to.be.a('object').that.has.all.keys( + 'mimes', 'minduration', 'maxduration', 'protocols', 'w', 'h' ) }); it('should hav wpar keys in environment object', function () { - const requests = spec.buildRequests(DEFAULT_VALID_VIDEO_REQUESTS, VALID_BIDDER_REQUEST); - const payload = JSON.parse(requests.data) - expect(payload).to.have.property('environment') - expect(payload.environment).to.be.a('object').that.have.property('wpar') - expect(payload.environment.wpar).to.be.a('object').that.has.keys('innerWidth', 'innerHeight') + const {data} = spec.buildRequests(DEFAULT_VALID_VIDEO_REQUESTS, VALID_BIDDER_REQUEST); + expect(data).to.have.property('environment') + expect(data.environment).to.be.a('object').that.have.property('wpar') + expect(data.environment.wpar).to.be.a('object').that.has.keys('innerWidth', 'innerHeight') }); }) describe('interpretResponse', () => { it('should return a valid bid array with a banner bid', () => { - const response = utils.deepClone(SERVER_RESPONSE_BANNER) - const interpreted = spec.interpretResponse(response) - expect(interpreted).to.be.a('array').that.has.lengthOf(1) - interpreted.forEach(value => { + const {data} = spec.buildRequests(DEFAULT_VALID_BANNER_REQUESTS, VALID_BIDDER_REQUEST) + const bids = spec.interpretResponse({body: SERVER_RESPONSE_BANNER}, { data }) + expect(bids).to.be.a('array').that.has.lengthOf(1) + bids.forEach(value => { expect(value).to.be.a('object').that.has.all.keys( - 'ad', 'cpm', 'creativeId', 'currency', 'height', 'mediaType', 'meta', 'netRevenue', 'requestId', 'ttl', 'width', 'dealId' + 'ad', 'cpm', 'creativeId', 'currency', 'height', 'mediaType', 'meta', 'netRevenue', 'requestId', 'ttl', 'width', 'burl', 'seatBidId', 'creative_id' ) }) }); - it('should return a valid bid array with a banner bid', () => { - const response = utils.deepClone(SERVER_RESPONSE_VIDEO) - const interpreted = spec.interpretResponse(response) - expect(interpreted).to.be.a('array').that.has.lengthOf(1) - interpreted.forEach(value => { + it('should return a valid bid array with a video bid', () => { + const {data} = spec.buildRequests(DEFAULT_VALID_VIDEO_REQUESTS, VALID_BIDDER_REQUEST) + const bids = spec.interpretResponse({body: SERVER_RESPONSE_VIDEO}, { data }) + expect(bids).to.be.a('array').that.has.lengthOf(1) + bids.forEach(value => { expect(value).to.be.a('object').that.has.all.keys( - 'vastUrl', 'cpm', 'creativeId', 'currency', 'height', 'mediaType', 'meta', 'netRevenue', 'requestId', 'ttl', 'width', 'dealId' + 'vastUrl', 'vastXml', 'playerHeight', 'playerWidth', 'cpm', 'creativeId', 'currency', 'height', 'mediaType', 'meta', 'netRevenue', 'requestId', 'ttl', 'width', 'burl', 'seatBidId', 'creative_id' ) }) }); it('should return a valid bid array with netRevenue', () => { - const response = utils.deepClone(SERVER_RESPONSE_BANNER) - response.body.bid[0].isNet = true - const interpreted = spec.interpretResponse(response) - expect(interpreted).to.be.a('array').that.has.lengthOf(1) - expect(interpreted[0].netRevenue).to.be.true - }); - - it('should return an empty bid array if one of seatbid entry is missing price property', () => { - const response = utils.deepClone(SERVER_RESPONSE_BANNER) - delete response.body.bid[0].price - const interpreted = spec.interpretResponse(response) - expect(interpreted).to.be.a('array').that.has.lengthOf(0) - }); - - it('should return an empty bid array if one of seatbid entry is missing adm property', () => { - const response = utils.deepClone(SERVER_RESPONSE_BANNER) - delete response.body.bid[0].adm - const interpreted = spec.interpretResponse(response) - expect(interpreted).to.be.a('array').that.has.lengthOf(0) - }); + const {data} = spec.buildRequests(DEFAULT_VALID_VIDEO_REQUESTS, VALID_BIDDER_REQUEST) + const bids = spec.interpretResponse({body: SERVER_RESPONSE_VIDEO}, { data }) + expect(bids).to.be.a('array').that.has.lengthOf(1) + expect(bids[0].netRevenue).to.be.true + }); + + // it('should return an empty bid array if one of seatbid entry is missing price property', () => { + // const response = utils.deepClone(SERVER_RESPONSE_BANNER) + // delete response.body.bid[0].price + // const interpreted = spec.interpretResponse(response) + // expect(interpreted).to.be.a('array').that.has.lengthOf(0) + // }); + + // it('should return an empty bid array if one of seatbid entry is missing adm property', () => { + // const response = utils.deepClone(SERVER_RESPONSE_BANNER) + // delete response.body.bid[0].adm + // const interpreted = spec.interpretResponse(response) + // expect(interpreted).to.be.a('array').that.has.lengthOf(0) + // }); }) describe('onBidWon', () => { @@ -622,34 +492,29 @@ describe('Aidem adapter', () => { expect(spec.onBidWon).to.exist.and.to.be.a('function') }); - it(`should send a valid bid won notice from web environment`, function () { - spec.onBidWon(WIN_NOTICE_WEB); - expect(server.requests.length).to.equal(1); - }); - - it(`should send a valid bid won notice from app environment`, function () { - spec.onBidWon(WIN_NOTICE_APP); + it(`should send a win notice`, function () { + spec.onBidWon(WIN_NOTICE); expect(server.requests.length).to.equal(1); }); }); - describe('onBidderError', () => { - it(`should exists and type function`, function () { - expect(spec.onBidderError).to.exist.and.to.be.a('function') - }); - - it(`should send a valid error notice`, function () { - spec.onBidderError({ bidderRequest: ERROR_NOTICE }) - expect(server.requests.length).to.equal(1); - const body = JSON.parse(server.requests[0].requestBody) - expect(body).to.be.a('object').that.has.all.keys('message', 'auctionId', 'bidderRequestId', 'url', 'metrics') - // const { bids } = JSON.parse(server.requests[0].requestBody) - // expect(bids).to.be.a('array').that.has.lengthOf(1) - // _each(bids, (bid) => { - // expect(bid).to.be.a('object').that.has.all.keys('adUnitCode', 'auctionId', 'bidId', 'bidderRequestId', 'transactionId', 'metrics') - // }) - }); - }); + // describe('onBidderError', () => { + // it(`should exists and type function`, function () { + // expect(spec.onBidderError).to.exist.and.to.be.a('function') + // }); + // + // it(`should send a valid error notice`, function () { + // spec.onBidderError({ bidderRequest: ERROR_NOTICE }) + // expect(server.requests.length).to.equal(1); + // const body = JSON.parse(server.requests[0].requestBody) + // expect(body).to.be.a('object').that.has.all.keys('message', 'auctionId', 'bidderRequestId', 'url', 'metrics') + // // const { bids } = JSON.parse(server.requests[0].requestBody) + // // expect(bids).to.be.a('array').that.has.lengthOf(1) + // // _each(bids, (bid) => { + // // expect(bid).to.be.a('object').that.has.all.keys('adUnitCode', 'auctionId', 'bidId', 'bidderRequestId', 'transactionId', 'metrics') + // // }) + // }); + // }); describe('setEndPoints', () => { it(`should exists and type function`, function () { @@ -659,64 +524,35 @@ describe('Aidem adapter', () => { it(`should not modify default endpoints`, function () { const endpoints = setEndPoints() const requestURL = new URL(endpoints.request) - const winNoticeURL = new URL(endpoints.notice.win) - const timeoutNoticeURL = new URL(endpoints.notice.timeout) - const errorNoticeURL = new URL(endpoints.notice.error) - expect(requestURL.host).to.equal('zero.aidemsrv.com') - expect(winNoticeURL.host).to.equal('zero.aidemsrv.com') - expect(timeoutNoticeURL.host).to.equal('zero.aidemsrv.com') - expect(errorNoticeURL.host).to.equal('zero.aidemsrv.com') - - expect(decodeURIComponent(requestURL.pathname)).to.equal('/bid/request') - expect(decodeURIComponent(winNoticeURL.pathname)).to.equal('/notice/win') - expect(decodeURIComponent(timeoutNoticeURL.pathname)).to.equal('/notice/timeout') - expect(decodeURIComponent(errorNoticeURL.pathname)).to.equal('/notice/error') + expect(decodeURIComponent(requestURL.pathname)).to.equal('/prebidjs/ortb/v2.6/bid/request') }); it(`should not change request endpoint`, function () { const endpoints = setEndPoints('default') const requestURL = new URL(endpoints.request) - expect(decodeURIComponent(requestURL.pathname)).to.equal('/bid/request') + expect(decodeURIComponent(requestURL.pathname)).to.equal('/prebidjs/ortb/v2.6/bid/request') }); it(`should change to local env`, function () { const endpoints = setEndPoints('local') const requestURL = new URL(endpoints.request) - const winNoticeURL = new URL(endpoints.notice.win) - const timeoutNoticeURL = new URL(endpoints.notice.timeout) - const errorNoticeURL = new URL(endpoints.notice.error) expect(requestURL.host).to.equal('127.0.0.1:8787') - expect(winNoticeURL.host).to.equal('127.0.0.1:8787') - expect(timeoutNoticeURL.host).to.equal('127.0.0.1:8787') - expect(errorNoticeURL.host).to.equal('127.0.0.1:8787') }); it(`should add a path prefix`, function () { const endpoints = setEndPoints('local', '/path') const requestURL = new URL(endpoints.request) - const winNoticeURL = new URL(endpoints.notice.win) - const timeoutNoticeURL = new URL(endpoints.notice.timeout) - const errorNoticeURL = new URL(endpoints.notice.error) - expect(decodeURIComponent(requestURL.pathname)).to.equal('/path/bid/request') - expect(decodeURIComponent(winNoticeURL.pathname)).to.equal('/path/notice/win') - expect(decodeURIComponent(timeoutNoticeURL.pathname)).to.equal('/path/notice/timeout') - expect(decodeURIComponent(errorNoticeURL.pathname)).to.equal('/path/notice/error') + expect(decodeURIComponent(requestURL.pathname)).to.equal('/path/prebidjs/ortb/v2.6/bid/request') }); it(`should add a path prefix and change request endpoint`, function () { const endpoints = setEndPoints('local', '/path') const requestURL = new URL(endpoints.request) - const winNoticeURL = new URL(endpoints.notice.win) - const timeoutNoticeURL = new URL(endpoints.notice.timeout) - const errorNoticeURL = new URL(endpoints.notice.error) - expect(decodeURIComponent(requestURL.pathname)).to.equal('/path/bid/request') - expect(decodeURIComponent(winNoticeURL.pathname)).to.equal('/path/notice/win') - expect(decodeURIComponent(timeoutNoticeURL.pathname)).to.equal('/path/notice/timeout') - expect(decodeURIComponent(errorNoticeURL.pathname)).to.equal('/path/notice/error') + expect(decodeURIComponent(requestURL.pathname)).to.equal('/path/prebidjs/ortb/v2.6/bid/request') }); }); @@ -758,8 +594,7 @@ describe('Aidem adapter', () => { coppa: true }); const { data } = spec.buildRequests(DEFAULT_VALID_BANNER_REQUESTS, VALID_BIDDER_REQUEST); - const request = JSON.parse(data) - expect(request.regs.coppa_applies).to.equal(true) + expect(data.regs.coppa_applies).to.equal(true) }); it(`should set gdpr to true`, function () { @@ -771,8 +606,7 @@ describe('Aidem adapter', () => { } }); const { data } = spec.buildRequests(DEFAULT_VALID_BANNER_REQUESTS, VALID_BIDDER_REQUEST); - const request = JSON.parse(data) - expect(request.regs.gdpr_applies).to.equal(true) + expect(data.regs.gdpr_applies).to.equal(true) }); it(`should set usp_consent string`, function () { @@ -789,8 +623,7 @@ describe('Aidem adapter', () => { } }); const { data } = spec.buildRequests(DEFAULT_VALID_BANNER_REQUESTS, VALID_BIDDER_REQUEST); - const request = JSON.parse(data) - expect(request.regs.us_privacy).to.equal('1YYY') + expect(data.regs.us_privacy).to.equal('1YYY') }); it(`should not set usp_consent string`, function () { @@ -807,8 +640,7 @@ describe('Aidem adapter', () => { } }); const { data } = spec.buildRequests(DEFAULT_VALID_BANNER_REQUESTS, VALID_BIDDER_REQUEST); - const request = JSON.parse(data) - expect(request.regs.us_privacy).to.undefined + expect(data.regs.us_privacy).to.undefined }); }); }); From 2986c1cf77ef4891c085f62b0d15ae6e235496f2 Mon Sep 17 00:00:00 2001 From: darkstar Date: Fri, 25 Aug 2023 06:17:13 +0200 Subject: [PATCH 16/21] disabled video-specific tests --- test/spec/modules/aidemBidAdapter_spec.js | 51 ++++++++++++----------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/test/spec/modules/aidemBidAdapter_spec.js b/test/spec/modules/aidemBidAdapter_spec.js index 14b21a53412..3de348197b2 100644 --- a/test/spec/modules/aidemBidAdapter_spec.js +++ b/test/spec/modules/aidemBidAdapter_spec.js @@ -5,7 +5,6 @@ import {deepSetValue} from '../../../src/utils'; import {server} from '../../mocks/xhr'; import {config} from '../../../src/config'; import {NATIVE} from '../../../src/mediaTypes.js'; -import {CONVERTER} from '../../../modules/improvedigitalBidAdapter'; // Full banner + Full Video + Basic Banner + Basic Video const VALID_BIDS = [ @@ -419,20 +418,22 @@ describe('Aidem adapter', () => { ) }); - it('should have a well formatted video payload', () => { - const {data} = spec.buildRequests(DEFAULT_VALID_VIDEO_REQUESTS, VALID_BIDDER_REQUEST); - expect(data).to.be.a('object').that.has.all.keys( - 'id', 'imp', 'regs', 'site', 'environment', 'at', 'test' - ) - expect(data.imp).to.be.a('array').that.has.lengthOf(DEFAULT_VALID_VIDEO_REQUESTS.length) + if (FEATURES.VIDEO) { + it('should have a well formatted video payload', () => { + const {data} = spec.buildRequests(DEFAULT_VALID_VIDEO_REQUESTS, VALID_BIDDER_REQUEST); + expect(data).to.be.a('object').that.has.all.keys( + 'id', 'imp', 'regs', 'site', 'environment', 'at', 'test' + ) + expect(data.imp).to.be.a('array').that.has.lengthOf(DEFAULT_VALID_VIDEO_REQUESTS.length) - expect(data.imp[0]).to.be.a('object').that.has.all.keys( - 'video', 'id', 'tagId' - ) - expect(data.imp[0].video).to.be.a('object').that.has.all.keys( - 'mimes', 'minduration', 'maxduration', 'protocols', 'w', 'h' - ) - }); + expect(data.imp[0]).to.be.a('object').that.has.all.keys( + 'video', 'id', 'tagId' + ) + expect(data.imp[0].video).to.be.a('object').that.has.all.keys( + 'mimes', 'minduration', 'maxduration', 'protocols', 'w', 'h' + ) + }); + } it('should hav wpar keys in environment object', function () { const {data} = spec.buildRequests(DEFAULT_VALID_VIDEO_REQUESTS, VALID_BIDDER_REQUEST); @@ -454,16 +455,18 @@ describe('Aidem adapter', () => { }) }); - it('should return a valid bid array with a video bid', () => { - const {data} = spec.buildRequests(DEFAULT_VALID_VIDEO_REQUESTS, VALID_BIDDER_REQUEST) - const bids = spec.interpretResponse({body: SERVER_RESPONSE_VIDEO}, { data }) - expect(bids).to.be.a('array').that.has.lengthOf(1) - bids.forEach(value => { - expect(value).to.be.a('object').that.has.all.keys( - 'vastUrl', 'vastXml', 'playerHeight', 'playerWidth', 'cpm', 'creativeId', 'currency', 'height', 'mediaType', 'meta', 'netRevenue', 'requestId', 'ttl', 'width', 'burl', 'seatBidId', 'creative_id' - ) - }) - }); + if (FEATURES.VIDEO) { + it('should return a valid bid array with a video bid', () => { + const {data} = spec.buildRequests(DEFAULT_VALID_VIDEO_REQUESTS, VALID_BIDDER_REQUEST) + const bids = spec.interpretResponse({body: SERVER_RESPONSE_VIDEO}, { data }) + expect(bids).to.be.a('array').that.has.lengthOf(1) + bids.forEach(value => { + expect(value).to.be.a('object').that.has.all.keys( + 'vastUrl', 'vastXml', 'playerHeight', 'playerWidth', 'cpm', 'creativeId', 'currency', 'height', 'mediaType', 'meta', 'netRevenue', 'requestId', 'ttl', 'width', 'burl', 'seatBidId', 'creative_id' + ) + }) + }); + } it('should return a valid bid array with netRevenue', () => { const {data} = spec.buildRequests(DEFAULT_VALID_VIDEO_REQUESTS, VALID_BIDDER_REQUEST) From a740a11e1b0c02940fadc8d4889b9d691644ec19 Mon Sep 17 00:00:00 2001 From: AndreaT Date: Mon, 27 May 2024 17:17:32 +0200 Subject: [PATCH 17/21] Fixed getConfig cleanup of consent management (Issue #10658) --- modules/aidemBidAdapter.js | 20 ++++--- test/spec/modules/aidemBidAdapter_spec.js | 73 +++++++++++++++++++---- 2 files changed, 72 insertions(+), 21 deletions(-) diff --git a/modules/aidemBidAdapter.js b/modules/aidemBidAdapter.js index c6a5cd96fb6..51dcad18a5b 100644 --- a/modules/aidemBidAdapter.js +++ b/modules/aidemBidAdapter.js @@ -13,6 +13,8 @@ const LOCAL_BASE_URL = 'http://127.0.0.1:8787'; const SUPPORTED_MEDIA_TYPES = [BANNER, VIDEO]; const REQUIRED_VIDEO_PARAMS = [ 'mimes', 'protocols', 'context' ]; +const pbjsVersion = '$prebid.version$'; + export const ERROR_CODES = { BID_SIZE_INVALID_FORMAT: 1, BID_SIZE_NOT_INCLUDED: 2, @@ -59,7 +61,7 @@ const converter = ortbConverter({ const request = buildRequest(imps, bidderRequest, context); deepSetValue(request, 'at', 1); setPrebidRequestEnvironment(request); - deepSetValue(request, 'regs', getRegs()); + deepSetValue(request, 'regs', getRegs(bidderRequest)); deepSetValue(request, 'site.publisher.id', bidderRequest.bids[0].params.publisherId); deepSetValue(request, 'site.id', bidderRequest.bids[0].params.siteId); return request; @@ -106,22 +108,22 @@ function recur(obj) { return result; } -function getRegs() { +function getRegs(bidderRequest) { let regs = {}; - const consentManagement = config.getConfig('consentManagement'); + const euConsentManagement = bidderRequest.gdprConsent; + const usConsentManagement = bidderRequest.uspConsent; const coppa = config.getConfig('coppa'); - if (consentManagement && !!(consentManagement.gdpr)) { - deepSetValue(regs, 'gdpr_applies', !!consentManagement.gdpr); + if (euConsentManagement && euConsentManagement.consentString) { + deepSetValue(regs, 'gdpr_applies', !!euConsentManagement.consentString); } else { deepSetValue(regs, 'gdpr_applies', false); } - if (consentManagement && deepAccess(consentManagement, 'usp.cmpApi') === 'static') { - deepSetValue(regs, 'usp_applies', !!deepAccess(consentManagement, 'usp')); - deepSetValue(regs, 'us_privacy', deepAccess(consentManagement, 'usp.consentData.getUSPData.uspString')); + if (usConsentManagement) { + deepSetValue(regs, 'usp_applies', true); + deepSetValue(regs, 'us_privacy', bidderRequest.uspConsent); } else { deepSetValue(regs, 'usp_applies', false); } - if (isBoolean(coppa)) { deepSetValue(regs, 'coppa_applies', !!coppa); } else { diff --git a/test/spec/modules/aidemBidAdapter_spec.js b/test/spec/modules/aidemBidAdapter_spec.js index 3de348197b2..48f6b3c079e 100644 --- a/test/spec/modules/aidemBidAdapter_spec.js +++ b/test/spec/modules/aidemBidAdapter_spec.js @@ -168,7 +168,7 @@ const DEFAULT_VALID_BANNER_REQUESTS = [ }, params: { siteId: '1', - placementId: '13144370' + placementId: '13144370', }, src: 'client', transactionId: 'db739693-9b4a-4669-9945-8eab938783cc' @@ -193,7 +193,7 @@ const DEFAULT_VALID_VIDEO_REQUESTS = [ }, params: { siteId: '1', - placementId: '13144370' + placementId: '13144370', }, src: 'client', transactionId: 'db739693-9b4a-4669-9945-8eab938783cc' @@ -209,7 +209,27 @@ const VALID_BIDDER_REQUEST = { params: { placementId: '13144370', siteId: '23434', - publisherId: '7689670753' + publisherId: '7689670753', + }, + } + ], + refererInfo: { + page: 'test-page', + domain: 'test-domain', + ref: 'test-referer' + }, +} + +const VALID_GDPR_BIDDER_REQUEST = { + auctionId: '19c97f22-5bd1-4b16-a128-80f75fb0a8a0', + bidderCode: 'aidem', + bidderRequestId: '1bbb7854dfa0d8', + bids: [ + { + params: { + placementId: '13144370', + siteId: '23434', + publisherId: '7689670753', }, } ], @@ -218,6 +238,30 @@ const VALID_BIDDER_REQUEST = { domain: 'test-domain', ref: 'test-referer' }, + gdprConsent: { + consentString: 'test-gdpr-string' + } +} + +const VALID_USP_BIDDER_REQUEST = { + auctionId: '19c97f22-5bd1-4b16-a128-80f75fb0a8a0', + bidderCode: 'aidem', + bidderRequestId: '1bbb7854dfa0d8', + bids: [ + { + params: { + placementId: '13144370', + siteId: '23434', + publisherId: '7689670753', + }, + } + ], + refererInfo: { + page: 'test-page', + domain: 'test-domain', + ref: 'test-referer' + }, + uspConsent: '1YYY' } const SERVER_RESPONSE_BANNER = { @@ -601,19 +645,24 @@ describe('Aidem adapter', () => { }); it(`should set gdpr to true`, function () { - config.setConfig({ + /* config.setConfig({ + consentManagement: { consentManagement: { gdpr: { - // any data here set gdpr to true + consentData: { + getTCData: { + tcString: 'Q1BsRDRFVVBsRDRFVUVXQUFBRU5DWkNBQUFBQUFBQUFBQUFBQUFBQUFBQUEuSUk3TmRfWF9fYlg5bi1fN182ZnQwZVkxZjlfcjM3dVF6RGhmTnMtOEYzTF9XX0x3WDMyRTdORjM2dHE0S21SNGt1MWJCSVFOdEhNblVEVW14YW9sVnJ6SHNhazJjcHlOS0pfSmtrbnNaZTJkWUdGOVBuOWxELVlLWjdfNV85X2Y1MlRfOV85Xy0zOXozXzlmX19fZHZfLV9fLXZqZl81OTluX3Y5ZlZfNzhfS2Y5X19fX19fLV9fX19fX19fX19fXzhB' + } + } }, } - }); - const { data } = spec.buildRequests(DEFAULT_VALID_BANNER_REQUESTS, VALID_BIDDER_REQUEST); + }); */ + const { data } = spec.buildRequests(DEFAULT_VALID_BANNER_REQUESTS, VALID_GDPR_BIDDER_REQUEST); expect(data.regs.gdpr_applies).to.equal(true) }); it(`should set usp_consent string`, function () { - config.setConfig({ + /* config.setConfig({ consentManagement: { usp: { cmpApi: 'static', @@ -624,13 +673,13 @@ describe('Aidem adapter', () => { } } } - }); - const { data } = spec.buildRequests(DEFAULT_VALID_BANNER_REQUESTS, VALID_BIDDER_REQUEST); + }); */ + const { data } = spec.buildRequests(DEFAULT_VALID_BANNER_REQUESTS, VALID_USP_BIDDER_REQUEST); expect(data.regs.us_privacy).to.equal('1YYY') }); it(`should not set usp_consent string`, function () { - config.setConfig({ + /*config.setConfig({ consentManagement: { usp: { cmpApi: 'iab', @@ -641,7 +690,7 @@ describe('Aidem adapter', () => { } } } - }); + });*/ const { data } = spec.buildRequests(DEFAULT_VALID_BANNER_REQUESTS, VALID_BIDDER_REQUEST); expect(data.regs.us_privacy).to.undefined }); From 4dc915948342c264c2fea58d4e4714fb2c4afe55 Mon Sep 17 00:00:00 2001 From: AndreaT Date: Tue, 28 May 2024 11:58:09 +0200 Subject: [PATCH 18/21] Fixed getConfig cleanup of consent management (Issue #10658) --- test/spec/modules/aidemBidAdapter_spec.js | 71 +++++++++++------------ 1 file changed, 35 insertions(+), 36 deletions(-) diff --git a/test/spec/modules/aidemBidAdapter_spec.js b/test/spec/modules/aidemBidAdapter_spec.js index 48f6b3c079e..8c826bf088d 100644 --- a/test/spec/modules/aidemBidAdapter_spec.js +++ b/test/spec/modules/aidemBidAdapter_spec.js @@ -645,52 +645,51 @@ describe('Aidem adapter', () => { }); it(`should set gdpr to true`, function () { - /* config.setConfig({ - consentManagement: { - consentManagement: { - gdpr: { - consentData: { - getTCData: { - tcString: 'Q1BsRDRFVVBsRDRFVUVXQUFBRU5DWkNBQUFBQUFBQUFBQUFBQUFBQUFBQUEuSUk3TmRfWF9fYlg5bi1fN182ZnQwZVkxZjlfcjM3dVF6RGhmTnMtOEYzTF9XX0x3WDMyRTdORjM2dHE0S21SNGt1MWJCSVFOdEhNblVEVW14YW9sVnJ6SHNhazJjcHlOS0pfSmtrbnNaZTJkWUdGOVBuOWxELVlLWjdfNV85X2Y1MlRfOV85Xy0zOXozXzlmX19fZHZfLV9fLXZqZl81OTluX3Y5ZlZfNzhfS2Y5X19fX19fLV9fX19fX19fX19fXzhB' - } - } - }, - } - }); */ + // config.setConfig({ + // consentManagement: { + // gdpr: { + // consentData: { + // getTCData: { + // tcString: 'Q1BsRDRFVVBsRDRFVUVXQUFBRU5DWkNBQUFBQUFBQUFBQUFBQUFBQUFBQUEuSUk3TmRfWF9fYlg5bi1fN182ZnQwZVkxZjlfcjM3dVF6RGhmTnMtOEYzTF9XX0x3WDMyRTdORjM2dHE0S21SNGt1MWJCSVFOdEhNblVEVW14YW9sVnJ6SHNhazJjcHlOS0pfSmtrbnNaZTJkWUdGOVBuOWxELVlLWjdfNV85X2Y1MlRfOV85Xy0zOXozXzlmX19fZHZfLV9fLXZqZl81OTluX3Y5ZlZfNzhfS2Y5X19fX19fLV9fX19fX19fX19fXzhB' + // } + // } + // }, + // } + // }); const { data } = spec.buildRequests(DEFAULT_VALID_BANNER_REQUESTS, VALID_GDPR_BIDDER_REQUEST); expect(data.regs.gdpr_applies).to.equal(true) }); it(`should set usp_consent string`, function () { - /* config.setConfig({ - consentManagement: { - usp: { - cmpApi: 'static', - consentData: { - getUSPData: { - uspString: '1YYY' - } - } - } - } - }); */ + // config.setConfig({ + // consentManagement: { + // usp: { + // cmpApi: 'static', + // consentData: { + // getUSPData: { + // uspString: '1YYY' + // } + // } + // } + // } + // }); const { data } = spec.buildRequests(DEFAULT_VALID_BANNER_REQUESTS, VALID_USP_BIDDER_REQUEST); expect(data.regs.us_privacy).to.equal('1YYY') }); it(`should not set usp_consent string`, function () { - /*config.setConfig({ - consentManagement: { - usp: { - cmpApi: 'iab', - consentData: { - getUSPData: { - uspString: '1YYY' - } - } - } - } - });*/ + // config.setConfig({ + // consentManagement: { + // usp: { + // cmpApi: 'iab', + // consentData: { + // getUSPData: { + // uspString: '1YYY' + // } + // } + // } + // } + // }); const { data } = spec.buildRequests(DEFAULT_VALID_BANNER_REQUESTS, VALID_BIDDER_REQUEST); expect(data.regs.us_privacy).to.undefined }); From fed53f6007fc045767b541034fd7b7dec712e5ad Mon Sep 17 00:00:00 2001 From: AndreaT Date: Tue, 28 May 2024 12:00:42 +0200 Subject: [PATCH 19/21] Fixed getConfig cleanup of consent management (Issue #10658) --- test/spec/modules/aidemBidAdapter_spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/spec/modules/aidemBidAdapter_spec.js b/test/spec/modules/aidemBidAdapter_spec.js index 8c826bf088d..c9d29ff09dd 100644 --- a/test/spec/modules/aidemBidAdapter_spec.js +++ b/test/spec/modules/aidemBidAdapter_spec.js @@ -650,7 +650,7 @@ describe('Aidem adapter', () => { // gdpr: { // consentData: { // getTCData: { - // tcString: 'Q1BsRDRFVVBsRDRFVUVXQUFBRU5DWkNBQUFBQUFBQUFBQUFBQUFBQUFBQUEuSUk3TmRfWF9fYlg5bi1fN182ZnQwZVkxZjlfcjM3dVF6RGhmTnMtOEYzTF9XX0x3WDMyRTdORjM2dHE0S21SNGt1MWJCSVFOdEhNblVEVW14YW9sVnJ6SHNhazJjcHlOS0pfSmtrbnNaZTJkWUdGOVBuOWxELVlLWjdfNV85X2Y1MlRfOV85Xy0zOXozXzlmX19fZHZfLV9fLXZqZl81OTluX3Y5ZlZfNzhfS2Y5X19fX19fLV9fX19fX19fX19fXzhB' + // tcString: 'test-gdpr-string' // } // } // }, From 88153732990985b8efe7a5c72ec127ccf1cd5dbf Mon Sep 17 00:00:00 2001 From: AndreaT Date: Tue, 28 May 2024 12:06:01 +0200 Subject: [PATCH 20/21] Fixed getConfig cleanup of consent management (Issue #10658) --- modules/aidemBidAdapter.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/modules/aidemBidAdapter.js b/modules/aidemBidAdapter.js index 51dcad18a5b..0730149e909 100644 --- a/modules/aidemBidAdapter.js +++ b/modules/aidemBidAdapter.js @@ -13,8 +13,6 @@ const LOCAL_BASE_URL = 'http://127.0.0.1:8787'; const SUPPORTED_MEDIA_TYPES = [BANNER, VIDEO]; const REQUIRED_VIDEO_PARAMS = [ 'mimes', 'protocols', 'context' ]; -const pbjsVersion = '$prebid.version$'; - export const ERROR_CODES = { BID_SIZE_INVALID_FORMAT: 1, BID_SIZE_NOT_INCLUDED: 2, From 12942d009535c41d8e7d2424e8575223fe9be902 Mon Sep 17 00:00:00 2001 From: AndreaT Date: Wed, 17 Jul 2024 10:36:41 +0200 Subject: [PATCH 21/21] Added gvlid param for Europe GDPR compliance --- modules/aidemBidAdapter.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/aidemBidAdapter.js b/modules/aidemBidAdapter.js index 3b55682b217..07aee262baa 100644 --- a/modules/aidemBidAdapter.js +++ b/modules/aidemBidAdapter.js @@ -10,6 +10,7 @@ const BIDDER_CODE = 'aidem'; const BASE_URL = 'https://zero.aidemsrv.com'; const LOCAL_BASE_URL = 'http://127.0.0.1:8787'; +const GVLID = 1218 const SUPPORTED_MEDIA_TYPES = [BANNER, VIDEO]; const REQUIRED_VIDEO_PARAMS = [ 'mimes', 'protocols', 'context' ]; @@ -232,6 +233,7 @@ function hasValidParameters(bidRequest) { export const spec = { code: BIDDER_CODE, + gvlid: GVLID, supportedMediaTypes: SUPPORTED_MEDIA_TYPES, isBidRequestValid: function(bidRequest) { logInfo('bid: ', bidRequest);