-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
ADman Media Adapter: compatible with version 5 and support uid2 (#7383)
* Add Adman bid adapter * Add supportedMediaTypes property * Update ADman Media bidder adapter * Remove console.log * Fix typo * revert package-json.lock * Delete package-lock.json * back to original package-lock.json * catch pbjs error * catch pbjs error * catch pbjs error * log * remove eu url * remove eu url * remove eu url * remove eu url * remove eu url * Update admanBidAdapter.js add consnet to sync url * Update admanBidAdapter.js fix import * Update admanBidAdapter.js lint fix * Update admanBidAdapter.js lint fix * Update admanBidAdapter.js check consent object data availability * сompatible with prebid v5 Co-authored-by: minoru katogi <mkatogi@gmail.com> Co-authored-by: minoru katogi <m_katogi@hotmail.com> Co-authored-by: ADman Media <admanmedia@users.noreply.github.com> Co-authored-by: SmartyAdman <adman@localhost.localdomain>
- Loading branch information
1 parent
906f908
commit 9f6daea
Showing
2 changed files
with
360 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
import {registerBidder} from '../src/adapters/bidderFactory.js'; | ||
import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js'; | ||
import * as utils from '../src/utils.js'; | ||
|
||
const BIDDER_CODE = 'adman'; | ||
const AD_URL = 'https://pub.admanmedia.com/?c=o&m=multi'; | ||
const URL_SYNC = 'https://pub.admanmedia.com/?c=o&m=sync'; | ||
|
||
function isBidResponseValid(bid) { | ||
if (!bid.requestId || !bid.cpm || !bid.creativeId || | ||
!bid.ttl || !bid.currency) { | ||
return false; | ||
} | ||
switch (bid['mediaType']) { | ||
case BANNER: | ||
return Boolean(bid.width && bid.height && bid.ad); | ||
case VIDEO: | ||
return Boolean(bid.vastUrl); | ||
case NATIVE: | ||
return Boolean(bid.native && bid.native.title && bid.native.image && bid.native.impressionTrackers); | ||
default: | ||
return false; | ||
} | ||
} | ||
|
||
function getBidFloor(bid) { | ||
if (!utils.isFn(bid.getFloor)) { | ||
return utils.deepAccess(bid, 'params.bidfloor', 0); | ||
} | ||
|
||
try { | ||
const bidFloor = bid.getFloor({ | ||
currency: 'USD', | ||
mediaType: '*', | ||
size: '*', | ||
}); | ||
return bidFloor.floor; | ||
} catch (_) { | ||
return 0 | ||
} | ||
} | ||
|
||
function getUserId(eids, id, source, uidExt) { | ||
if (id) { | ||
var uid = { id }; | ||
if (uidExt) { | ||
uid.ext = uidExt; | ||
} | ||
eids.push({ | ||
source, | ||
uids: [ uid ] | ||
}); | ||
} | ||
} | ||
|
||
export const spec = { | ||
code: BIDDER_CODE, | ||
supportedMediaTypes: [BANNER, VIDEO, NATIVE], | ||
|
||
isBidRequestValid: (bid) => { | ||
return Boolean(bid.bidId && bid.params && !isNaN(bid.params.placementId)); | ||
}, | ||
|
||
buildRequests: (validBidRequests = [], bidderRequest) => { | ||
let winTop = window; | ||
let location; | ||
try { | ||
location = new URL(bidderRequest.refererInfo.referer) | ||
winTop = window.top; | ||
} catch (e) { | ||
location = winTop.location; | ||
utils.logMessage(e); | ||
}; | ||
let placements = []; | ||
let request = { | ||
'deviceWidth': winTop.screen.width, | ||
'deviceHeight': winTop.screen.height, | ||
'language': (navigator && navigator.language) ? navigator.language : '', | ||
'secure': 1, | ||
'host': location.host, | ||
'page': location.pathname, | ||
'placements': placements | ||
}; | ||
request.language.indexOf('-') != -1 && (request.language = request.language.split('-')[0]) | ||
if (bidderRequest) { | ||
if (bidderRequest.uspConsent) { | ||
request.ccpa = bidderRequest.uspConsent; | ||
} | ||
if (bidderRequest.gdprConsent) { | ||
request.gdpr = bidderRequest.gdprConsent | ||
} | ||
} | ||
const len = validBidRequests.length; | ||
|
||
for (let i = 0; i < len; i++) { | ||
let bid = validBidRequests[i]; | ||
let traff = bid.params.traffic || BANNER | ||
const placement = { | ||
placementId: bid.params.placementId, | ||
bidId: bid.bidId, | ||
sizes: bid.mediaTypes && bid.mediaTypes[traff] && bid.mediaTypes[traff].sizes ? bid.mediaTypes[traff].sizes : [], | ||
traffic: traff, | ||
eids: [], | ||
bidFloor: getBidFloor(bid) | ||
} | ||
if (bid.schain) { | ||
placement.schain = bid.schain; | ||
} | ||
if (bid.userId) { | ||
getUserId(placement.eids, bid.userId.uid2 && bid.userId.uid2.id, 'uidapi.com'); | ||
} | ||
if (traff === VIDEO) { | ||
placement.playerSize = bid.mediaTypes[VIDEO].playerSize; | ||
placement.minduration = bid.mediaTypes[VIDEO].minduration; | ||
placement.maxduration = bid.mediaTypes[VIDEO].maxduration; | ||
placement.mimes = bid.mediaTypes[VIDEO].mimes; | ||
placement.protocols = bid.mediaTypes[VIDEO].protocols; | ||
placement.startdelay = bid.mediaTypes[VIDEO].startdelay; | ||
placement.placement = bid.mediaTypes[VIDEO].placement; | ||
placement.skip = bid.mediaTypes[VIDEO].skip; | ||
placement.skipafter = bid.mediaTypes[VIDEO].skipafter; | ||
placement.minbitrate = bid.mediaTypes[VIDEO].minbitrate; | ||
placement.maxbitrate = bid.mediaTypes[VIDEO].maxbitrate; | ||
placement.delivery = bid.mediaTypes[VIDEO].delivery; | ||
placement.playbackmethod = bid.mediaTypes[VIDEO].playbackmethod; | ||
placement.api = bid.mediaTypes[VIDEO].api; | ||
placement.linearity = bid.mediaTypes[VIDEO].linearity; | ||
} | ||
placements.push(placement); | ||
} | ||
return { | ||
method: 'POST', | ||
url: AD_URL, | ||
data: request | ||
}; | ||
}, | ||
|
||
interpretResponse: (serverResponse) => { | ||
let response = []; | ||
serverResponse = serverResponse.body; | ||
for (let i = 0; i < serverResponse.length; i++) { | ||
let resItem = serverResponse[i]; | ||
if (isBidResponseValid(resItem)) { | ||
const advertiserDomains = resItem.adomain && resItem.adomain.length ? resItem.adomain : []; | ||
resItem.meta = { ...resItem.meta, advertiserDomains }; | ||
|
||
response.push(resItem); | ||
} | ||
} | ||
return response; | ||
}, | ||
|
||
getUserSyncs: (syncOptions, serverResponses, gdprConsent, uspConsent) => { | ||
let syncUrl = URL_SYNC | ||
if (gdprConsent && gdprConsent.consentString) { | ||
if (typeof gdprConsent.gdprApplies === 'boolean') { | ||
syncUrl += `&gdpr=${Number(gdprConsent.gdprApplies)}&gdpr_consent=${gdprConsent.consentString}`; | ||
} else { | ||
syncUrl += `&gdpr==0&gdpr_consent=${gdprConsent.consentString}`; | ||
} | ||
} | ||
if (uspConsent && uspConsent.consentString) { | ||
syncUrl += `&ccpa_consent=${uspConsent.consentString}`; | ||
} | ||
return [{ | ||
type: 'image', | ||
url: syncUrl | ||
}]; | ||
} | ||
|
||
}; | ||
|
||
registerBidder(spec); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,187 @@ | ||
import {expect} from 'chai'; | ||
import {spec} from '../../../modules/admanBidAdapter.js'; | ||
|
||
describe('AdmanAdapter', function () { | ||
let bid = { | ||
bidId: '2dd581a2b6281d', | ||
bidder: 'adman', | ||
bidderRequestId: '145e1d6a7837c9', | ||
params: { | ||
placementId: 0 | ||
}, | ||
placementCode: 'placementid_0', | ||
auctionId: '74f78609-a92d-4cf1-869f-1b244bbfb5d2', | ||
mediaTypes: { | ||
banner: { | ||
sizes: [[300, 250]] | ||
} | ||
}, | ||
transactionId: '3bb2f6da-87a6-4029-aeb0-bfe951372e62', | ||
schain: { | ||
ver: '1.0', | ||
complete: 1, | ||
nodes: [ | ||
{ | ||
asi: 'example.com', | ||
sid: '0', | ||
hp: 1, | ||
rid: 'bidrequestid', | ||
// name: 'alladsallthetime', | ||
domain: 'example.com' | ||
} | ||
] | ||
} | ||
}; | ||
let bidderRequest = { | ||
bidderCode: 'adman', | ||
auctionId: 'fffffff-ffff-ffff-ffff-ffffffffffff', | ||
bidderRequestId: 'ffffffffffffff', | ||
start: 1472239426002, | ||
auctionStart: 1472239426000, | ||
timeout: 5000, | ||
uspConsent: '1YN-', | ||
refererInfo: { | ||
referer: 'http://www.example.com', | ||
reachedTop: true, | ||
}, | ||
bids: [bid] | ||
} | ||
|
||
describe('isBidRequestValid', function () { | ||
it('Should return true when placementId can be cast to a number', function () { | ||
expect(spec.isBidRequestValid(bid)).to.be.true; | ||
}); | ||
it('Should return false when placementId is not a number', function () { | ||
bid.params.placementId = 'aaa'; | ||
expect(spec.isBidRequestValid(bid)).to.be.false; | ||
}); | ||
}); | ||
|
||
describe('buildRequests', function () { | ||
let serverRequest = spec.buildRequests([bid], bidderRequest); | ||
it('Creates a ServerRequest object with method, URL and data', function () { | ||
expect(serverRequest).to.exist; | ||
expect(serverRequest.method).to.exist; | ||
expect(serverRequest.url).to.exist; | ||
expect(serverRequest.data).to.exist; | ||
}); | ||
it('Returns POST method', function () { | ||
expect(serverRequest.method).to.equal('POST'); | ||
}); | ||
it('Returns valid URL', function () { | ||
expect(serverRequest.url).to.equal('https://pub.admanmedia.com/?c=o&m=multi'); | ||
}); | ||
it('Should contain ccpa', function() { | ||
expect(serverRequest.data.ccpa).to.be.an('string') | ||
}) | ||
|
||
it('Returns valid data if array of bids is valid', function () { | ||
let data = serverRequest.data; | ||
expect(data).to.be.an('object'); | ||
expect(data).to.have.all.keys('deviceWidth', 'deviceHeight', 'language', 'secure', 'host', 'page', 'placements', 'ccpa'); | ||
expect(data.deviceWidth).to.be.a('number'); | ||
expect(data.deviceHeight).to.be.a('number'); | ||
expect(data.language).to.be.a('string'); | ||
expect(data.secure).to.be.within(0, 1); | ||
expect(data.host).to.be.a('string'); | ||
expect(data.page).to.be.a('string'); | ||
let placements = data['placements']; | ||
for (let i = 0; i < placements.length; i++) { | ||
let placement = placements[i]; | ||
expect(placement).to.have.all.keys('placementId', 'eids', 'bidId', 'traffic', 'sizes', 'schain', 'bidFloor'); | ||
expect(placement.schain).to.be.an('object') | ||
expect(placement.placementId).to.be.a('number'); | ||
expect(placement.bidId).to.be.a('string'); | ||
expect(placement.traffic).to.be.a('string'); | ||
expect(placement.sizes).to.be.an('array'); | ||
expect(placement.bidFloor).to.be.an('number'); | ||
} | ||
}); | ||
it('Returns empty data if no valid requests are passed', function () { | ||
serverRequest = spec.buildRequests([]); | ||
let data = serverRequest.data; | ||
expect(data.placements).to.be.an('array').that.is.empty; | ||
}); | ||
}); | ||
|
||
describe('buildRequests with user ids', function () { | ||
bid.userId = {} | ||
bid.userId.uid2 = { id: 'uid2id123' }; | ||
let serverRequest = spec.buildRequests([bid], bidderRequest); | ||
it('Returns valid data if array of bids is valid', function () { | ||
let data = serverRequest.data; | ||
let placements = data['placements']; | ||
expect(data).to.be.an('object'); | ||
for (let i = 0; i < placements.length; i++) { | ||
let placement = placements[i]; | ||
expect(placement).to.have.property('eids') | ||
expect(placement.eids).to.be.an('array') | ||
expect(placement.eids.length).to.be.equal(1) | ||
for (let index in placement.eids) { | ||
let v = placement.eids[index]; | ||
expect(v).to.have.all.keys('source', 'uids') | ||
expect(v.source).to.be.oneOf(['uidapi.com']) | ||
expect(v.uids).to.be.an('array'); | ||
expect(v.uids.length).to.be.equal(1) | ||
expect(v.uids[0]).to.have.property('id') | ||
} | ||
} | ||
}); | ||
}); | ||
|
||
describe('interpretResponse', function () { | ||
let resObject = { | ||
body: [ { | ||
requestId: '123', | ||
mediaType: 'banner', | ||
cpm: 0.3, | ||
width: 320, | ||
height: 50, | ||
ad: '<h1>Hello ad</h1>', | ||
ttl: 1000, | ||
creativeId: '123asd', | ||
netRevenue: true, | ||
currency: 'USD', | ||
meta: { | ||
advertiserDomains: ['google.com'], | ||
advertiserId: 1234 | ||
} | ||
} ] | ||
}; | ||
let serverResponses = spec.interpretResponse(resObject); | ||
it('Returns an array of valid server responses if response object is valid', function () { | ||
expect(serverResponses).to.be.an('array').that.is.not.empty; | ||
for (let i = 0; i < serverResponses.length; i++) { | ||
let dataItem = serverResponses[i]; | ||
expect(dataItem).to.have.all.keys('requestId', 'cpm', 'width', 'height', 'ad', 'ttl', 'creativeId', | ||
'netRevenue', 'currency', 'mediaType', 'meta'); | ||
expect(dataItem.requestId).to.be.a('string'); | ||
expect(dataItem.cpm).to.be.a('number'); | ||
expect(dataItem.width).to.be.a('number'); | ||
expect(dataItem.height).to.be.a('number'); | ||
expect(dataItem.ad).to.be.a('string'); | ||
expect(dataItem.ttl).to.be.a('number'); | ||
expect(dataItem.creativeId).to.be.a('string'); | ||
expect(dataItem.netRevenue).to.be.a('boolean'); | ||
expect(dataItem.currency).to.be.a('string'); | ||
expect(dataItem.mediaType).to.be.a('string'); | ||
expect(dataItem.meta).to.be.an('object').that.has.any.key('advertiserDomains'); | ||
} | ||
it('Returns an empty array if invalid response is passed', function () { | ||
serverResponses = spec.interpretResponse('invalid_response'); | ||
expect(serverResponses).to.be.an('array').that.is.empty; | ||
}); | ||
}); | ||
}); | ||
|
||
describe('getUserSyncs', function () { | ||
let userSync = spec.getUserSyncs(); | ||
it('Returns valid URL and type', function () { | ||
expect(userSync).to.be.an('array').with.lengthOf(1); | ||
expect(userSync[0].type).to.exist; | ||
expect(userSync[0].url).to.exist; | ||
expect(userSync[0].type).to.be.equal('image'); | ||
expect(userSync[0].url).to.be.equal('https://pub.admanmedia.com/?c=o&m=sync'); | ||
}); | ||
}); | ||
}); |