Skip to content

Commit

Permalink
TheMediaGrid & TrustX bid adapters: reformat first party data (#8146)
Browse files Browse the repository at this point in the history
* Added TheMediaGridNM Bid Adapter

* Updated required params for TheMediaGridNM Bid Adapter

* Update TheMediGridNM Bid Adapter

* Fix tests for TheMediaGridNM Bid Adapter

* Fixes after review for TheMediaGridNM Bid Adapter

* Add support of multi-format in TheMediaGrid Bid Adapter

* Update sync url for grid and gridNM Bid Adapters

* TheMediaGrid Bid Adapter: added keywords adUnit parameter

* Update TheMediaGrid Bid Adapter to support keywords from config

* Implement new request format for TheMediaGrid Bid Adapter

* Fix jwpseg params for TheMediaGrid Bid Adapter

* Update unit tests for The Media Grid Bid Adapter

* Fix typo in TheMediaGrid Bid Adapter

* Added test for jwTargeting in TheMediaGrid Bid Adapter

* The new request format was made by default in TheMediaGrid Bid Adapter

* Update userId format in ad request for TheMediaGrid Bid Adapter

* Added bidFloor parameter for TheMediaGrid Bid Adapter

* Fix for review TheMediaGrid Bid Adapter

* Support floorModule in TheMediaGrid Bid Adapter

* Fix empty bidfloor for TheMediaGrid Bid Adapter

* Some change to restart autotests

* Fix userIds format for TheMediaGrid Bid Adapter

* Remove digitrust userId from TheMediaGrid Bid Adapter

* Protocols was added in video section in ad request for TheMediaGrid Bid Adapter

* TheMediaGrid: fix trouble with alias using

* TheMediaGridNM: fix trouble with alias

* TheMediaGrid Bid Adapter: added support of PBAdSlot module

* TheMediaGrid Bid Adapter: fix typo

* GridNM Bid Adapter: use absent in params data from mediaTypes

* GridNM Bid Adapter: fix md file + add advertiserDomains support

* TheMediaGrid and gridNM Bid Adapter: minor netRevenue fixes

* gridNM Bid Adapter updates after review

* TheMediaGrid Bid Adapter: fix keywords workflow

* fix testing and kick off lgtm again

* TheMediaGrid: added ext.bidder.grid.demandSource processing

* TheMediaGrid: added user.id from fpd cookie

* TheMediaGrid: control cookie setting via bidder config

* TheMediaGrid: use localStorage instead cookie

* TheMediaGridNM Bid Adapter: update adapter to use /hbjson endpoint

* TheMediaGridNM: fix unnecessary conditions

* TheMediaGrid: fix bug with nurl field in response

* TheMediaGrid: update test

* TheMediaGridNM: fix possible bug with nurl

* TheMediaGrid: added alias as playwire

* TheMediaGrid: added alias as adlivetech

* TheMediaGrid: fix sync url workflow

* TrustX: fix sync url worflow + remove old syncurl

* TheMediaGrid: added instl support

* TheMediaGrid: fix test for instl

* TheMediaGrid: update md file

* TheMediaGrid: reformat segments for permutive rtd module

* TrustX: send all ortb2.user.data in user.data

* TheMediaGrid: remove permutive segments reformating

* TrustX: remove permutive segments reformating

* TheMediaGrid & TrustX: fix typo

Co-authored-by: Chris Huie <phoenixtechnerd@gmail.com>
  • Loading branch information
TheMediaGrid and ChrisHuie authored Mar 16, 2022
1 parent c4e0c5f commit 3ca2ef1
Show file tree
Hide file tree
Showing 5 changed files with 196 additions and 69 deletions.
24 changes: 20 additions & 4 deletions modules/gridBidAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -171,9 +171,7 @@ export const spec = {
user = {
data: [{
name: 'iow_labs_pub_data',
segment: jwpseg.map((seg) => {
return {name: 'jwpseg', value: seg};
})
segment: segmentProcessing(jwpseg, 'jwpseg'),
}]
};
}
Expand All @@ -183,7 +181,9 @@ export const spec = {
if (!user) {
user = { data: [] };
}
user = mergeDeep(user, { data: ortb2UserData });
user = mergeDeep(user, {
data: [...ortb2UserData]
});
}

if (gdprConsent && gdprConsent.consentString) {
Expand Down Expand Up @@ -489,6 +489,22 @@ function getUserIdFromFPDStorage() {
return storage.getDataFromLocalStorage(USER_ID_KEY) || makeNewUserIdInFPDStorage();
}

function segmentProcessing(segment, forceSegName) {
return segment
.map((seg) => {
const value = seg && (seg.value || seg.id || seg);
if (typeof value === 'string' || typeof value === 'number') {
return {
value: value.toString(),
...(forceSegName && { name: forceSegName }),
...(seg.name && { name: seg.name }),
};
}
return null;
})
.filter((seg) => !!seg);
}

function reformatKeywords(pageKeywords) {
const formatedPageKeywords = {};
Object.keys(pageKeywords).forEach((name) => {
Expand Down
33 changes: 23 additions & 10 deletions modules/gridBidAdapter.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,23 @@ Grid bid adapter supports Banner and Video (instream and outstream).
You can allow writing in localStorage `pbjs.setBidderConfig` for the bidder `grid`
```
pbjs.setBidderConfig({
bidders: ["grid"],
config: {
localStorageWriteAllowed: true
}
})
bidders: ["grid"],
config: {
localStorageWriteAllowed: true
}
})
```

# Test Parameters
```
var adUnits = [
{
code: 'test-div',
sizes: [[300, 250]],
mediaTypes: {
banner: {
sizes: [[300, 250], [300,600]],
}
},
bids: [
{
bidder: "grid",
Expand All @@ -37,15 +41,19 @@ pbjs.setBidderConfig({
]
},{
code: 'test-div',
sizes: [[728, 90]],
bids: [
{
bidder: "grid",
params: {
uid: 2,
keywords: {
brandsafety: ['disaster'],
topic: ['stress', 'fear']
site: {
publisher: [{
name: 'someKeywordsName',
brandsafety: ['disaster'],
topic: ['stress', 'fear']
}]
}
}
}
}
Expand All @@ -54,7 +62,12 @@ pbjs.setBidderConfig({
{
code: 'test-div',
sizes: [[728, 90]],
mediaTypes: { video: {} },
mediaTypes: {
video: {
playerSize: [1280, 720],
context: 'instream'
}
},
bids: [
{
bidder: "grid",
Expand Down
64 changes: 30 additions & 34 deletions modules/trustxBidAdapter.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { isEmpty, deepAccess, logError, logWarn, parseGPTSingleSizeArrayToRtbSize } from '../src/utils.js';
import {isEmpty, deepAccess, logError, logWarn, parseGPTSingleSizeArrayToRtbSize, mergeDeep} from '../src/utils.js';
import {registerBidder} from '../src/adapters/bidderFactory.js';
import { Renderer } from '../src/Renderer.js';
import { VIDEO, BANNER } from '../src/mediaTypes.js';
Expand All @@ -21,6 +21,7 @@ const LOG_ERROR_MESS = {
hasEmptySeatbidArray: 'Response has empty seatbid array',
hasNoArrayOfBids: 'Seatbid from response has no array of bid objects - '
};

export const spec = {
code: BIDDER_CODE,
supportedMediaTypes: [ BANNER, VIDEO ],
Expand Down Expand Up @@ -173,16 +174,25 @@ export const spec = {
request.site.content = content;
}

const userData = [];
addSegments('iow_labs_pub_data', 'jwpseg', jwpseg, userData);
addSegments('permutive', 'p_standard', permutiveseg, userData, 'permutive.com');

if (userData.length) {
if (jwpseg && jwpseg.length) {
user = {
data: userData
data: [{
name: 'iow_labs_pub_data',
segment: segmentProcessing(jwpseg, 'jwpseg'),
}]
};
}

const ortb2UserData = config.getConfig('ortb2.user.data');
if (ortb2UserData && ortb2UserData.length) {
if (!user) {
user = { data: [] };
}
user = mergeDeep(user, {
data: [...ortb2UserData]
});
}

if (gdprConsent && gdprConsent.consentString) {
userExt = {consent: gdprConsent.consentString};
}
Expand Down Expand Up @@ -431,34 +441,20 @@ function createBannerRequest(bid, mediaType) {
return result;
}

function addSegments(name, segName, segments, data, bidConfigName) {
if (segments && segments.length) {
data.push({
name: name,
segment: segments
.map((seg) => seg && (seg.id || seg))
.filter((seg) => seg && (typeof seg === 'string' || typeof seg === 'number'))
.map((seg) => ({ name: segName, value: seg.toString() }))
});
} else if (bidConfigName) {
const configData = config.getConfig('ortb2.user.data');
let segData = null;
configData && configData.some(({name, segment}) => {
if (name === bidConfigName) {
segData = segment;
return true;
function segmentProcessing(segment, forceSegName) {
return segment
.map((seg) => {
const value = seg && (seg.value || seg.id || seg);
if (typeof value === 'string' || typeof value === 'number') {
return {
value: value.toString(),
...(forceSegName && { name: forceSegName }),
...(seg.name && { name: seg.name }),
};
}
});
if (segData && segData.length) {
data.push({
name: name,
segment: segData
.map((seg) => seg && (seg.id || seg))
.filter((seg) => seg && (typeof seg === 'string' || typeof seg === 'number'))
.map((seg) => ({ name: segName, value: seg.toString() }))
});
}
}
return null;
})
.filter((seg) => !!seg);
}

function reformatKeywords(pageKeywords) {
Expand Down
68 changes: 66 additions & 2 deletions test/spec/modules/gridBidAdapter_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -546,7 +546,71 @@ describe('TheMediaGrid Adapter', function () {
getConfigStub.restore();
});

it('shold be right tmax when timeout in config is less then timeout in bidderRequest', function() {
it('should have user.data filled from config ortb2.user.data', function () {
const userData = [
{
name: 'someName',
segment: [1, 2, { anyKey: 'anyVal' }, 'segVal', { id: 'segId' }, { value: 'segValue' }, { id: 'segId2', name: 'segName' }]
},
{
name: 'permutive.com',
segment: [1, 2, 'segVal', { id: 'segId' }, { anyKey: 'anyVal' }, { value: 'segValue' }, { id: 'segId2', name: 'segName' }]
},
{
someKey: 'another data'
}
];

const getConfigStub = sinon.stub(config, 'getConfig').callsFake(
arg => arg === 'ortb2.user.data' ? userData : null);
const request = spec.buildRequests([bidRequests[0]], bidderRequest);
const payload = parseRequest(request.data);
expect(payload.user.data).to.deep.equal(userData);
getConfigStub.restore();
});

it('should have right value in user.data when jwpsegments are present', function () {
const userData = [
{
name: 'someName',
segment: [1, 2, { anyKey: 'anyVal' }, 'segVal', { id: 'segId' }, { value: 'segValue' }, { id: 'segId2', name: 'segName' }]
},
{
name: 'permutive.com',
segment: [1, 2, 'segVal', { id: 'segId' }, { anyKey: 'anyVal' }, { value: 'segValue' }, { id: 'segId2', name: 'segName' }]
},
{
someKey: 'another data'
}
];
const getConfigStub = sinon.stub(config, 'getConfig').callsFake(
arg => arg === 'ortb2.user.data' ? userData : null);

const jsContent = {id: 'test_jw_content_id'};
const jsSegments = ['test_seg_1', 'test_seg_2'];
const bidRequestsWithJwTargeting = Object.assign({}, bidRequests[0], {
rtd: {
jwplayer: {
targeting: {
segments: jsSegments,
content: jsContent
}
}
}
});
const request = spec.buildRequests([bidRequestsWithJwTargeting], bidderRequest);
const payload = parseRequest(request.data);
expect(payload.user.data).to.deep.equal([{
name: 'iow_labs_pub_data',
segment: [
{name: 'jwpseg', value: jsSegments[0]},
{name: 'jwpseg', value: jsSegments[1]}
]
}, ...userData]);
getConfigStub.restore();
});

it('should be right tmax when timeout in config is less then timeout in bidderRequest', function() {
const getConfigStub = sinon.stub(config, 'getConfig').callsFake(
arg => arg === 'bidderTimeout' ? 2000 : null);
const request = spec.buildRequests([bidRequests[0]], bidderRequest);
Expand All @@ -555,7 +619,7 @@ describe('TheMediaGrid Adapter', function () {
expect(payload.tmax).to.equal(2000);
getConfigStub.restore();
});
it('shold be right tmax when timeout in bidderRequest is less then timeout in config', function() {
it('should be right tmax when timeout in bidderRequest is less then timeout in config', function() {
const getConfigStub = sinon.stub(config, 'getConfig').callsFake(
arg => arg === 'bidderTimeout' ? 5000 : null);
const request = spec.buildRequests([bidRequests[0]], bidderRequest);
Expand Down
76 changes: 57 additions & 19 deletions test/spec/modules/trustxBidAdapter_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -401,30 +401,68 @@ describe('TrustXAdapter', function () {
expect(payload.site.content).to.deep.equal(jsContent);
});

it('if segment is present in permutive targeting, payload must have right params', function () {
const permSegments = [{id: 'test_perm_1'}, {id: 'test_perm_2'}];
const bidRequestsWithPermutiveTargeting = bidRequests.map((bid) => {
return Object.assign({
rtd: {
p_standard: {
targeting: {
segments: permSegments
}
it('should have user.data filled from config ortb2.user.data', function () {
const userData = [
{
name: 'someName',
segment: [1, 2, { anyKey: 'anyVal' }, 'segVal', { id: 'segId' }, { value: 'segValue' }, { id: 'segId2', name: 'segName' }]
},
{
name: 'permutive.com',
segment: [1, 2, 'segVal', { id: 'segId' }, { anyKey: 'anyVal' }, { value: 'segValue' }, { id: 'segId2', name: 'segName' }]
},
{
someKey: 'another data'
}
];

const getConfigStub = sinon.stub(config, 'getConfig').callsFake(
arg => arg === 'ortb2.user.data' ? userData : null);
const request = spec.buildRequests([bidRequests[0]], bidderRequest);
const payload = parseRequest(request.data);
expect(payload.user.data).to.deep.equal(userData);
getConfigStub.restore();
});

it('should have right value in user.data when jwpsegments are present', function () {
const userData = [
{
name: 'someName',
segment: [1, 2, { anyKey: 'anyVal' }, 'segVal', { id: 'segId' }, { value: 'segValue' }, { id: 'segId2', name: 'segName' }]
},
{
name: 'permutive.com',
segment: [1, 2, 'segVal', { id: 'segId' }, { anyKey: 'anyVal' }, { value: 'segValue' }, { id: 'segId2', name: 'segName' }]
},
{
someKey: 'another data'
}
];
const getConfigStub = sinon.stub(config, 'getConfig').callsFake(
arg => arg === 'ortb2.user.data' ? userData : null);

const jsContent = {id: 'test_jw_content_id'};
const jsSegments = ['test_seg_1', 'test_seg_2'];
const bidRequestsWithJwTargeting = Object.assign({}, bidRequests[0], {
rtd: {
jwplayer: {
targeting: {
segments: jsSegments,
content: jsContent
}
}
}, bid);
}
});
const request = spec.buildRequests(bidRequestsWithPermutiveTargeting, bidderRequest);
expect(request.data).to.be.an('string');
const request = spec.buildRequests([bidRequestsWithJwTargeting], bidderRequest);
const payload = parseRequest(request.data);
expect(payload).to.have.property('user');
expect(payload.user.data).to.deep.equal([{
name: 'permutive',
name: 'iow_labs_pub_data',
segment: [
{name: 'p_standard', value: permSegments[0].id},
{name: 'p_standard', value: permSegments[1].id}
{name: 'jwpseg', value: jsSegments[0]},
{name: 'jwpseg', value: jsSegments[1]}
]
}]);
}, ...userData]);
getConfigStub.restore();
});

it('should contain the keyword values if it present in ortb2.(site/user)', function () {
Expand Down Expand Up @@ -501,7 +539,7 @@ describe('TrustXAdapter', function () {
getConfigStub.restore();
});

it('shold be right tmax when timeout in config is less then timeout in bidderRequest', function() {
it('should be right tmax when timeout in config is less then timeout in bidderRequest', function() {
const getConfigStub = sinon.stub(config, 'getConfig').callsFake(
arg => arg === 'bidderTimeout' ? 2000 : null);
const request = spec.buildRequests([bidRequests[0]], bidderRequest);
Expand All @@ -510,7 +548,7 @@ describe('TrustXAdapter', function () {
expect(payload.tmax).to.equal(2000);
getConfigStub.restore();
});
it('shold be right tmax when timeout in bidderRequest is less then timeout in config', function() {
it('should be right tmax when timeout in bidderRequest is less then timeout in config', function() {
const getConfigStub = sinon.stub(config, 'getConfig').callsFake(
arg => arg === 'bidderTimeout' ? 5000 : null);
const request = spec.buildRequests([bidRequests[0]], bidderRequest);
Expand Down

0 comments on commit 3ca2ef1

Please sign in to comment.