From 51bcf81bc6212de26290168a789c6db16d53af90 Mon Sep 17 00:00:00 2001 From: kalidas-alkimi <92875788+kalidas-alkimi@users.noreply.github.com> Date: Thu, 25 Apr 2024 16:54:20 +0100 Subject: [PATCH] Alkimi Bid Adapter : add handling for user-sync URL and pass custom object with bid request (#11326) * Alkimi bid adapter * Alkimi bid adapter * Alkimi bid adapter * alkimi adapter * onBidWon change * sign utils * auction ID as bid request ID * unit test fixes * change maintainer info * Updated the ad unit params * features support added * transfer adUnitCode * transfer adUnitCode: test * AlkimiBidAdapter getFloor() using * ALK-504 Multi size ad slot support * ALK-504 Multi size ad slot support * Support new OpenRTB parameters * Support new oRTB2 parameters * remove pos parameter * Add gvl_id into Alkimi adapter * Insert keywords into bid-request param * Resolve AUCTION_PRICE macro on prebid-server for VAST ads * Added support for full page auction * Added custom user object * userParams in request object * Handling user-sync url, store user id and passing custom params * Renamed the full_page_auction to fpa * Updated the review comment --------- Co-authored-by: Alexander <32703851+pro-nsk@users.noreply.github.com> Co-authored-by: Alexander Bogdanov Co-authored-by: Alexander Bogdanov Co-authored-by: motors Co-authored-by: mihanikw2g <92710748+mihanikw2g@users.noreply.github.com> Co-authored-by: Nikulin Mikhail Co-authored-by: mik --- modules/alkimiBidAdapter.js | 56 ++++++++++++++++++---- test/spec/modules/alkimiBidAdapter_spec.js | 16 +++++-- 2 files changed, 59 insertions(+), 13 deletions(-) diff --git a/modules/alkimiBidAdapter.js b/modules/alkimiBidAdapter.js index d4e7cab8ed1..3bd995cc112 100644 --- a/modules/alkimiBidAdapter.js +++ b/modules/alkimiBidAdapter.js @@ -1,12 +1,15 @@ import {registerBidder} from '../src/adapters/bidderFactory.js'; import {deepAccess, deepClone, getDNT, generateUUID, replaceAuctionPrice} from '../src/utils.js'; import {ajax} from '../src/ajax.js'; +import {getStorageManager} from '../src/storageManager.js'; import {VIDEO, BANNER} from '../src/mediaTypes.js'; import {config} from '../src/config.js'; const BIDDER_CODE = 'alkimi'; const GVLID = 1169; +const USER_ID_KEY = 'alkimiUserID'; export const ENDPOINT = 'https://exchange.alkimi-onboarding.com/bid?prebid=true'; +export const storage = getStorageManager({bidderCode: BIDDER_CODE}); export const spec = { code: BIDDER_CODE, @@ -43,11 +46,16 @@ export const spec = { bidIds.push(bidRequest.bidId) }) + const ortb2 = bidderRequest.ortb2 + const site = ortb2?.site + + const id = getUserId() const alkimiConfig = config.getConfig('alkimi') - const fullPageAuction = bidderRequest.ortb2?.source?.ext?.full_page_auction - const source = fullPageAuction != undefined ? { ext: { full_page_auction: fullPageAuction } } : undefined + const fpa = ortb2?.source?.ext?.fpa + const source = fpa != undefined ? { ext: { fpa } } : undefined const walletID = alkimiConfig && alkimiConfig.walletID - const user = walletID != undefined ? { ext: { walletID: walletID } } : undefined + const userParams = alkimiConfig && alkimiConfig.userParams + const user = (walletID != undefined || userParams != undefined || id != undefined) ? { id, ext: { walletID, userParams } } : undefined let payload = { requestId: generateUUID(), @@ -66,11 +74,14 @@ export const spec = { source, user, site: { - keywords: bidderRequest.ortb2?.site?.keywords + keywords: site?.keywords, + sectioncat: site?.sectioncat, + pagecat: site?.pagecat, + cat: site?.cat }, - at: bidderRequest.ortb2?.at, - bcat: bidderRequest.ortb2?.bcat, - wseat: bidderRequest.ortb2?.wseat + at: ortb2?.at, + bcat: ortb2?.bcat, + wseat: ortb2?.wseat } } @@ -111,7 +122,7 @@ export const spec = { } const {prebidResponse} = serverBody; - if (!prebidResponse || typeof prebidResponse !== 'object') { + if (!Array.isArray(prebidResponse)) { return []; } @@ -141,6 +152,24 @@ export const spec = { return true; } return false; + }, + + getUserSyncs: function(syncOptions, serverResponses, gdprConsent) { + if (syncOptions.iframeEnabled && serverResponses.length > 0) { + const serverBody = serverResponses[0].body; + if (!serverBody || typeof serverBody !== 'object') return []; + + const { iframeList } = serverBody; + if (!Array.isArray(iframeList)) return []; + + const urls = []; + iframeList.forEach(url => { + urls.push({type: 'iframe', url}); + }) + + return urls; + } + return []; } } @@ -175,4 +204,15 @@ const getFormatType = bidRequest => { return formats } +const getUserId = () => { + if (storage.localStorageIsEnabled()) { + let userId = storage.getDataFromLocalStorage(USER_ID_KEY) + if (!userId) { + userId = generateUUID() + storage.setDataInLocalStorage(USER_ID_KEY, userId) + } + return userId + } +} + registerBidder(spec); diff --git a/test/spec/modules/alkimiBidAdapter_spec.js b/test/spec/modules/alkimiBidAdapter_spec.js index 90a9e409e69..e551d98fa07 100644 --- a/test/spec/modules/alkimiBidAdapter_spec.js +++ b/test/spec/modules/alkimiBidAdapter_spec.js @@ -91,11 +91,11 @@ describe('alkimiBidAdapter', function () { }) it('should return false when required params are not passed', function () { - let bid = Object.assign({}, REQUEST) + let bid = JSON.parse(JSON.stringify(REQUEST)) delete bid.params.token expect(spec.isBidRequestValid(bid)).to.equal(false) - bid = Object.assign({}, REQUEST) + bid = JSON.parse(JSON.stringify(REQUEST)) delete bid.params expect(spec.isBidRequestValid(bid)).to.equal(false) }) @@ -115,29 +115,35 @@ describe('alkimiBidAdapter', function () { uspConsent: 'uspConsent', ortb2: { site: { - keywords: 'test1, test2' + keywords: 'test1, test2', + cat: ['IAB2'], + pagecat: ['IAB3'], + sectioncat: ['IAB4'] }, at: 2, bcat: ['BSW1', 'BSW2'], wseat: ['16', '165'] } } - const bidderRequest = spec.buildRequests(bidRequests, requestData) it('should return a properly formatted request with eids defined', function () { + const bidderRequest = spec.buildRequests(bidRequests, requestData) expect(bidderRequest.data.eids).to.deep.equal(REQUEST.userIdAsEids) }) it('should return a properly formatted request with gdpr defined', function () { + const bidderRequest = spec.buildRequests(bidRequests, requestData) expect(bidderRequest.data.gdprConsent.consentRequired).to.equal(true) expect(bidderRequest.data.gdprConsent.consentString).to.equal('test-consent') }) it('should return a properly formatted request with uspConsent defined', function () { + const bidderRequest = spec.buildRequests(bidRequests, requestData) expect(bidderRequest.data.uspConsent).to.equal('uspConsent') }) it('sends bid request to ENDPOINT via POST', function () { + const bidderRequest = spec.buildRequests(bidRequests, requestData) expect(bidderRequest.method).to.equal('POST') expect(bidderRequest.data.requestId).to.not.equal(undefined) expect(bidderRequest.data.referer).to.equal('http://test.com/path.html') @@ -146,7 +152,7 @@ describe('alkimiBidAdapter', function () { expect(bidderRequest.data.signRequest.randomUUID).to.equal(undefined) expect(bidderRequest.data.bidIds).to.deep.contains('456') expect(bidderRequest.data.signature).to.equal(undefined) - expect(bidderRequest.data.ortb2).to.deep.contains({ at: 2, wseat: ['16', '165'], bcat: ['BSW1', 'BSW2'], site: { keywords: 'test1, test2' }, }) + expect(bidderRequest.data.ortb2).to.deep.contains({ at: 2, wseat: ['16', '165'], bcat: ['BSW1', 'BSW2'], site: { keywords: 'test1, test2', cat: ['IAB2'], pagecat: ['IAB3'], sectioncat: ['IAB4'] } }) expect(bidderRequest.options.customHeaders).to.deep.equal({ 'Rtb-Direct': true }) expect(bidderRequest.options.contentType).to.equal('application/json') expect(bidderRequest.url).to.equal(ENDPOINT)