Skip to content

Commit

Permalink
OpenX Bid Adapter: Handle site.content.data & bug fixes (prebid#7576)
Browse files Browse the repository at this point in the history
* make OpenX bid adapter send data from site.content.data

* lint

* fix merkleId for openxBidAdapter

Co-authored-by: Brian Schmidt <brian.schmidt@openx.com>
  • Loading branch information
2 people authored and Chris Pabst committed Jan 10, 2022
1 parent a3e26ee commit cacc0b2
Show file tree
Hide file tree
Showing 2 changed files with 145 additions and 35 deletions.
56 changes: 34 additions & 22 deletions modules/openxBidAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -256,27 +256,14 @@ function buildCommonQueryParamsFromBids(bids, bidderRequest) {
nocache: new Date().getTime()
};

const firstPartyData = config.getConfig('ortb2.user.data')
if (Array.isArray(firstPartyData) && firstPartyData.length > 0) {
// extract and merge valid segments by provider/taxonomy
const fpd = firstPartyData
.filter(
data => (Array.isArray(data.segment) &&
data.segment.length > 0 &&
data.name !== undefined &&
data.name.length > 0)
)
.reduce((acc, data) => {
const name = typeof data.ext === 'object' && data.ext.segtax ? `${data.name}/${data.ext.segtax}` : data.name;
acc[name] = (acc[name] || []).concat(data.segment.map(seg => seg.id));
return acc;
}, {})
const sm = Object.keys(fpd)
.map((name, _) => name + ':' + fpd[name].join('|'))
.join(',')
if (sm.length > 0) {
defaultParams.sm = encodeURIComponent(sm);
}
const userDataSegments = buildFpdQueryParams('ortb2.user.data');
if (userDataSegments.length > 0) {
defaultParams.sm = userDataSegments;
}

const siteContentDataSegments = buildFpdQueryParams('ortb2.site.content.data');
if (siteContentDataSegments.length > 0) {
defaultParams.scsm = siteContentDataSegments;
}

if (bids[0].params.platform) {
Expand Down Expand Up @@ -317,12 +304,37 @@ function buildCommonQueryParamsFromBids(bids, bidderRequest) {
return defaultParams;
}

function buildFpdQueryParams(fpdPath) {
const firstPartyData = config.getConfig(fpdPath);
if (!Array.isArray(firstPartyData) || !firstPartyData.length) {
return '';
}
const fpd = firstPartyData
.filter(
data => (Array.isArray(data.segment) &&
data.segment.length > 0 &&
data.name !== undefined &&
data.name.length > 0)
)
.reduce((acc, data) => {
const name = typeof data.ext === 'object' && data.ext.segtax ? `${data.name}/${data.ext.segtax}` : data.name;
acc[name] = (acc[name] || []).concat(data.segment.map(seg => seg.id));
return acc;
}, {})
return Object.keys(fpd)
.map((name, _) => name + ':' + [...new Set(fpd[name])].join('|'))
.join(',')
}

function appendUserIdsToQueryParams(queryParams, userIds) {
_each(userIds, (userIdObjectOrValue, userIdProviderKey) => {
const key = USER_ID_CODE_TO_QUERY_ARG[userIdProviderKey];

if (USER_ID_CODE_TO_QUERY_ARG.hasOwnProperty(userIdProviderKey)) {
switch (userIdProviderKey) {
case 'merkleId':
queryParams[key] = userIdObjectOrValue.id;
break;
case 'flocId':
queryParams[key] = userIdObjectOrValue.id;
break;
Expand All @@ -333,7 +345,7 @@ function appendUserIdsToQueryParams(queryParams, userIds) {
queryParams[key] = userIdObjectOrValue.lipbid;
if (Array.isArray(userIdObjectOrValue.segments) && userIdObjectOrValue.segments.length > 0) {
const liveIntentSegments = 'liveintent:' + userIdObjectOrValue.segments.join('|')
queryParams.sm = `${queryParams.sm ? queryParams.sm + encodeURIComponent(',') : ''}${encodeURIComponent(liveIntentSegments)}`;
queryParams.sm = `${queryParams.sm ? queryParams.sm + ',' : ''}${liveIntentSegments}`;
}
break;
case 'parrableId':
Expand Down
124 changes: 111 additions & 13 deletions test/spec/modules/openxBidAdapter_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -1085,7 +1085,7 @@ describe('OpenxAdapter', function () {
intentIqId: '1111-intentiqid',
lipb: {lipbid: '1111-lipb'},
lotamePanoramaId: '1111-lotameid',
merkleId: '1111-merkleid',
merkleId: {id: '1111-merkleid'},
netId: 'fH5A3n2O8_CZZyPoJVD-eabc6ECb7jhxCicsds7qSg',
parrableId: { eid: 'eidVersion.encryptionKeyReference.encryptedValue' },
pubcid: '1111-pubcid',
Expand Down Expand Up @@ -1139,6 +1139,9 @@ describe('OpenxAdapter', function () {
let userIdValue;
// handle cases where userId key refers to an object
switch (userIdProviderKey) {
case 'merkleId':
userIdValue = EXAMPLE_DATA_BY_ATTR.merkleId.id;
break;
case 'flocId':
userIdValue = EXAMPLE_DATA_BY_ATTR.flocId.id;
break;
Expand Down Expand Up @@ -1545,7 +1548,7 @@ describe('OpenxAdapter', function () {
describe('with segments', function () {
const TESTS = [
{
name: 'should send proprietary segment data from first party config',
name: 'should send proprietary segment data from ortb2.user.data',
config: {
ortb2: {
user: {
Expand All @@ -1556,10 +1559,77 @@ describe('OpenxAdapter', function () {
}
}
},
expect: 'dmp1/4:foo|bar,dmp2:baz',
expect: {sm: 'dmp1/4:foo|bar,dmp2:baz'},
},
{
name: 'should send proprietary segment data from ortb2.site.content.data',
config: {
ortb2: {
site: {
content: {
data: [
{name: 'dmp1', ext: {segtax: 4}, segment: [{id: 'foo'}, {id: 'bar'}]},
{name: 'dmp2', segment: [{id: 'baz'}]},
]
}
}
}
},
expect: {scsm: 'dmp1/4:foo|bar,dmp2:baz'},
},
{
name: 'should send proprietary segment data from both ortb2.site.content.data and ortb2.user.data',
config: {
ortb2: {
user: {
data: [
{name: 'dmp1', ext: {segtax: 4}, segment: [{id: 'foo'}, {id: 'bar'}]},
{name: 'dmp2', segment: [{id: 'baz'}]},
]
},
site: {
content: {
data: [
{name: 'dmp3', ext: {segtax: 5}, segment: [{id: 'foo2'}, {id: 'bar2'}]},
{name: 'dmp4', segment: [{id: 'baz2'}]},
]
}
}
}
},
expect: {
sm: 'dmp1/4:foo|bar,dmp2:baz',
scsm: 'dmp3/5:foo2|bar2,dmp4:baz2'
},
},
{
name: 'should not send duplicate proprietary segment data from first party config ',
config: {
ortb2: {
user: {
data: [
{name: 'dmp1', ext: {segtax: 4}, segment: [{id: 'foo'}, {id: 'bar'}, {id: 'foo'}]},
{name: 'dmp1', ext: {segtax: 4}, segment: [{id: 'foo'}, {id: 'bar'}]},
]
},
site: {
content: {
data: [
{name: 'dmp1', ext: {segtax: 4}, segment: [{id: 'foo'}, {id: 'bar'}]},
{name: 'dmp3', ext: {segtax: 5}, segment: [{id: 'foo2'}, {id: 'foo2'}, {id: 'bar2'}]},
{name: 'dmp3', ext: {segtax: 5}, segment: [{id: 'foo2'}, {id: 'bar2'}]},
]
}
}
}
},
expect: {
sm: 'dmp1/4:foo|bar',
scsm: 'dmp1/4:foo|bar,dmp3/5:foo2|bar2'
},
},
{
name: 'should combine same provider segment data from first party config',
name: 'should combine same provider segment data from ortb2.user.data',
config: {
ortb2: {
user: {
Expand All @@ -1570,7 +1640,23 @@ describe('OpenxAdapter', function () {
}
}
},
expect: 'dmp1/4:foo|bar,dmp1:baz',
expect: {sm: 'dmp1/4:foo|bar,dmp1:baz'},
},
{
name: 'should combine same provider segment data from ortb2.site.content.data',
config: {
ortb2: {
site: {
content: {
data: [
{name: 'dmp1', ext: {segtax: 4}, segment: [{id: 'foo'}, {id: 'bar'}]},
{name: 'dmp1', ext: {}, segment: [{id: 'baz'}]},
]
}
}
}
},
expect: {scsm: 'dmp1/4:foo|bar,dmp1:baz'},
},
{
name: 'should not send any segment data if first party config is incomplete',
Expand All @@ -1595,6 +1681,14 @@ describe('OpenxAdapter', function () {
{name: 'dmp1', segment: [{id: 'foo'}, {id: 'bar'}]},
{name: 'dmp2', segment: [{id: 'baz'}]},
]
},
site: {
content: {
data: [
{name: 'dmp3', ext: {segtax: 5}, segment: [{id: 'foo2'}, {id: 'bar2'}]},
{name: 'dmp4', segment: [{id: 'baz2'}]},
]
}
}
}
},
Expand All @@ -1606,7 +1700,10 @@ describe('OpenxAdapter', function () {
},
},
},
expect: 'dmp1:foo|bar,dmp2:baz,liveintent:l1|l2',
expect: {
sm: 'dmp1:foo|bar,dmp2:baz,liveintent:l1|l2',
scsm: 'dmp3/5:foo2|bar2,dmp4:baz2'
},
},
{
name: 'should send just liveintent segment from request if no first party config',
Expand All @@ -1619,7 +1716,7 @@ describe('OpenxAdapter', function () {
},
},
},
expect: 'liveintent:l1|l2',
expect: {sm: 'liveintent:l1|l2'},
},
{
name: 'should send nothing if lipb section does not contain segments',
Expand All @@ -1636,13 +1733,11 @@ describe('OpenxAdapter', function () {
utils._each(TESTS, (t) => {
context('in ortb2.user.data', function () {
let bidRequests;
let configStub;

beforeEach(function () {
let fpdConfig = t.config
configStub = sinon
sinon
.stub(config, 'getConfig')
.withArgs('ortb2.user.data')
.withArgs(sinon.match(/^ortb2\.user\.data$|^ortb2\.site\.content\.data$/))
.callsFake((key) => {
return utils.deepAccess(fpdConfig, key);
});
Expand All @@ -1658,10 +1753,13 @@ describe('OpenxAdapter', function () {
const request = spec.buildRequests(bidRequests, mockBidderRequest)
expect(request.length).to.equal(1);
if (t.expect) {
expect(request[0].data.sm).to.exist;
expect(request[0].data.sm).to.equal(encodeURIComponent(t.expect));
for (const key in t.expect) {
expect(request[0].data[key]).to.exist;
expect(request[0].data[key]).to.equal(t.expect[key]);
}
} else {
expect(request[0].data.sm).to.not.exist;
expect(request[0].data.scsm).to.not.exist;
}
});
});
Expand Down

0 comments on commit cacc0b2

Please sign in to comment.