Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

airgridRtdProvider: update ortb2 user data setting method #10080

Merged
merged 1 commit into from
Jun 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 24 additions & 53 deletions modules/airgridRtdProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,11 @@
* @module modules/airgridRtdProvider
* @requires module:modules/realTimeData
*/
import { config } from '../src/config.js';
import { submodule } from '../src/hook.js';
import {
deepSetValue,
deepAccess,
} from '../src/utils.js';
import { getGlobal } from '../src/prebidGlobal.js';
import { getStorageManager } from '../src/storageManager.js';
import { loadExternalScript } from '../src/adloader.js';
import { MODULE_TYPE_RTD } from '../src/activities/modules.js';
import {submodule} from '../src/hook.js';
import {deepAccess, deepSetValue, mergeDeep} from '../src/utils.js';
import {getStorageManager} from '../src/storageManager.js';
import {loadExternalScript} from '../src/adloader.js';
import {MODULE_TYPE_RTD} from '../src/activities/modules.js';

const MODULE_NAME = 'realTimeData';
const SUBMODULE_NAME = 'airgrid';
Expand Down Expand Up @@ -62,54 +57,35 @@ export function getMatchedAudiencesFromStorage() {
}
}

/**
* Mutates the adUnits object
* @param {Object} adUnits
* @param {Array} audiences
* @return {void}
*/
function setAudiencesToAppNexusAdUnits(adUnits, audiences) {
adUnits.forEach((adUnit) => {
adUnit.bids.forEach((bid) => {
if (bid.bidder && bid.bidder === 'appnexus') {
deepSetValue(bid, 'params.keywords.perid', audiences || []);
}
});
});
}

/**
* Pass audience data to configured bidders, using ORTB2
* @param {Object} bidConfig
* @param {Object} rtdConfig
* @param {Array} audiences
* @return {{}} a map from bidder code to ORTB2 config
* @return {void}
*/
export function setAudiencesAsBidderOrtb2(rtdConfig, audiences) {
export function setAudiencesAsBidderOrtb2(bidConfig, rtdConfig, audiences) {
const bidders = deepAccess(rtdConfig, 'params.bidders');
if (!bidders || bidders.length === 0 || !audiences || audiences.length === 0) return;

const keywords = audiences.map(
(audienceId) => `perid=${audienceId}`
).join(',');
const agOrtb2 = {};

config.mergeBidderConfig({
bidders: bidders,
config: {
ortb2: {
site: {
keywords,
}
}
const agUserData = [
{
id: String(AG_TCF_ID),
ext: {
segtax: 540,
},
name: 'airgrid',
segment: audiences.map((id) => ({id}))
}
})
}
]
deepSetValue(agOrtb2, 'user.data', agUserData);

export function setAudiencesUsingAppNexusAuctionKeywords(audiences) {
config.setConfig({
appnexusAuctionKeywords: {
perid: audiences,
},
Comment on lines -108 to -111
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dgirardi Are you 100% certain that we should not be using the appnexus specific method - have they removed this in v8?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, however, this change would break the integration for v7 - so good catch. (I did not realize appnexus' keyword logic was only in the v8 branch).

I'll rebase this PR against 8 soon - we are currently hoping to update the appnexus adapter to pick up user.data so I may try to account for that.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is still accessible to publishers but not rtd modules

});
const bidderConfig = Object.fromEntries(
bidders.map((bidder) => [bidder, agOrtb2])
)
mergeDeep(bidConfig?.ortb2Fragments?.bidder, bidderConfig)
}

/**
Expand Down Expand Up @@ -137,14 +113,9 @@ export function passAudiencesToBidders(
rtdConfig,
userConsent
) {
const adUnits = bidConfig.adUnits || getGlobal().adUnits;
const audiences = getMatchedAudiencesFromStorage();
if (audiences.length > 0) {
setAudiencesUsingAppNexusAuctionKeywords(audiences);
setAudiencesAsBidderOrtb2(rtdConfig, audiences)
if (adUnits) {
setAudiencesToAppNexusAdUnits(adUnits, audiences);
}
patmmccann marked this conversation as resolved.
Show resolved Hide resolved
setAudiencesAsBidderOrtb2(bidConfig, rtdConfig, audiences)
}
onDone();
}
Expand Down
68 changes: 9 additions & 59 deletions test/spec/modules/airgridRtdProvider_spec.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { config } from 'src/config.js';
import { deepAccess } from 'src/utils.js';
import { getAdUnits } from '../../fixtures/fixtures.js';
import {config} from 'src/config.js';
import {deepAccess} from 'src/utils.js';
import * as agRTD from 'modules/airgridRtdProvider.js';
import { loadExternalScript } from '../../../src/adloader.js';
import {loadExternalScript} from '../../../src/adloader.js';

const MATCHED_AUDIENCES = ['travel', 'sport'];
const RTD_CONFIG = {
Expand Down Expand Up @@ -71,73 +70,24 @@ describe('airgrid RTD Submodule', function () {
});

describe('Add matched audiences', function () {
it('merges matched audiences on appnexus AdUnits', function () {
const adUnits = getAdUnits();
getDataFromLocalStorageStub
.withArgs(agRTD.AG_AUDIENCE_IDS_KEY)
.returns(JSON.stringify(MATCHED_AUDIENCES));
agRTD.passAudiencesToBidders({ adUnits }, () => {}, {}, {});

adUnits.forEach((adUnit) => {
adUnit.bids.forEach((bid) => {
const { bidder, params } = bid;
if (bidder === 'appnexus') {
expect(deepAccess(params, 'keywords.perid')).to.eql(
MATCHED_AUDIENCES
);
}
});
});
});

it('does not merge audiences on appnexus adunits, since none are matched', function () {
const adUnits = getAdUnits();
getDataFromLocalStorageStub
.withArgs(agRTD.AG_AUDIENCE_IDS_KEY)
.returns(undefined);
agRTD.passAudiencesToBidders({ adUnits }, () => {}, {}, {});

adUnits.forEach((adUnit) => {
adUnit.bids.forEach((bid) => {
const { bidder, params } = bid;
if (bidder === 'appnexus') {
expect(deepAccess(params, 'keywords.perid')).to.be.undefined;
}
});
});
});

it('sets bidder specific ORTB2 config', function () {
getDataFromLocalStorageStub
.withArgs(agRTD.AG_AUDIENCE_IDS_KEY)
.returns(JSON.stringify(MATCHED_AUDIENCES));
const audiences = agRTD.getMatchedAudiencesFromStorage();

agRTD.setAudiencesAsBidderOrtb2(RTD_CONFIG.dataProviders[0], audiences);
const bidderOrtb2 = {};

agRTD.setAudiencesAsBidderOrtb2({ortb2Fragments: {bidder: bidderOrtb2}}, RTD_CONFIG.dataProviders[0], audiences);

const bidderConfig = config.getBidderConfig()
const bidders = RTD_CONFIG.dataProviders[0].params.bidders
const bidderOrtb2 = bidderConfig

Object.keys(bidderOrtb2).forEach((bidder) => {
if (bidders.indexOf(bidder) === -1) return;
bidders.forEach((bidder) => {
const ortb2 = bidderOrtb2[bidder];
MATCHED_AUDIENCES.forEach((audience) => {
expect(deepAccess(bidderOrtb2[bidder], 'ortb2.site.keywords')).to.contain(audience);
expect(ortb2.user.data[0].segment.find(segment => segment.id === audience)).to.exist;
})
});
});

it('sets audiences using appnexus auction level keywords', function () {
getDataFromLocalStorageStub
.withArgs(agRTD.AG_AUDIENCE_IDS_KEY)
.returns(JSON.stringify(MATCHED_AUDIENCES));
const audiences = agRTD.getMatchedAudiencesFromStorage();
agRTD.setAudiencesUsingAppNexusAuctionKeywords(audiences);

const bidderConfig = config.getConfig();
expect(deepAccess(bidderConfig, 'appnexusAuctionKeywords.perid')).to.eql(
MATCHED_AUDIENCES
);
});
});
});