Skip to content

Commit

Permalink
Send placeholders for configured native assets (prebid#3573)
Browse files Browse the repository at this point in the history
* Send placeholders for configured native assets

* Post native assets on replacement request

* Update names

* Change config name
  • Loading branch information
matthewlane authored and jsnellbaker committed Feb 27, 2019
1 parent fcbaa4c commit 99977a9
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 7 deletions.
6 changes: 3 additions & 3 deletions src/auction.js
Original file line number Diff line number Diff line change
Expand Up @@ -488,7 +488,7 @@ function getPreparedBidForAuction({adUnitCode, bid, bidderRequest, auctionId}) {
// if there is any key value pairs to map do here
var keyValues;
if (bidObject.bidderCode && (bidObject.cpm > 0 || bidObject.dealId)) {
keyValues = getKeyValueTargetingPairs(bidObject.bidderCode, bidObject);
keyValues = getKeyValueTargetingPairs(bidObject.bidderCode, bidObject, bidReq);
}

// use any targeting provided as defaults, otherwise just set from getKeyValueTargetingPairs
Expand Down Expand Up @@ -563,7 +563,7 @@ export function getStandardBidderSettings(mediaType) {
return bidderSettings[CONSTANTS.JSON_MAPPING.BD_SETTING_STANDARD];
}

export function getKeyValueTargetingPairs(bidderCode, custBidObj) {
export function getKeyValueTargetingPairs(bidderCode, custBidObj, bidReq) {
if (!custBidObj) {
return {};
}
Expand All @@ -586,7 +586,7 @@ export function getKeyValueTargetingPairs(bidderCode, custBidObj) {

// set native key value targeting
if (custBidObj['native']) {
keyValues = Object.assign({}, keyValues, getNativeTargeting(custBidObj));
keyValues = Object.assign({}, keyValues, getNativeTargeting(custBidObj, bidReq));
}

return keyValues;
Expand Down
35 changes: 33 additions & 2 deletions src/native.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { deepAccess, getBidRequest, logError, triggerPixel, insertHtmlIntoIframe } from './utils';
import { deepAccess, getBidRequest, getKeyByValue, insertHtmlIntoIframe, logError, triggerPixel } from './utils';
import includes from 'core-js/library/fn/array/includes';

const CONSTANTS = require('./constants.json');
Expand Down Expand Up @@ -151,7 +151,7 @@ export function fireNativeTrackers(message, adObject) {
* @param {Object} bid
* @return {Object} targeting
*/
export function getNativeTargeting(bid) {
export function getNativeTargeting(bid, bidReq) {
let keyValues = {};

Object.keys(bid['native']).forEach(asset => {
Expand All @@ -163,10 +163,41 @@ export function getNativeTargeting(bid) {
value = value.url;
}

const sendPlaceholder = deepAccess(
bidReq,
`mediaTypes.native.${asset}.sendId`
);

if (sendPlaceholder) {
const placeholder = `${key}:${bid.adId}`;
value = placeholder;
}

if (key && value) {
keyValues[key] = value;
}
});

return keyValues;
}

/**
* Constructs a message object containing asset values for each of the
* requested data keys.
*/
export function getAssetMessage(data, adObject) {
const message = {
message: 'assetResponse',
adId: data.adId,
assets: [],
};

data.assets.forEach(asset => {
const key = getKeyByValue(CONSTANTS.NATIVE_KEYS, asset);
const value = adObject.native[key];

message.assets.push({ key, value });
});

return message;
}
8 changes: 7 additions & 1 deletion src/secureCreatives.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*/

import events from './events';
import { fireNativeTrackers } from './native';
import { fireNativeTrackers, getAssetMessage } from './native';
import { EVENTS } from './constants';
import { isSlotMatchingAdUnitCode, logWarn, replaceAuctionPrice } from './utils';
import { auctionManager } from './auctionManager';
Expand Down Expand Up @@ -46,6 +46,12 @@ function receiveMessage(ev) {
// adId: '%%PATTERN:hb_adid%%'
// }), '*');
if (data.message === 'Prebid Native') {
if (data.action === 'assetRequest') {
const message = getAssetMessage(data, adObject);
ev.source.postMessage(JSON.stringify(message), ev.origin);
return;
}

fireNativeTrackers(data, adObject);
auctionManager.addWinningBid(adObject);
events.emit(BID_WON, adObject);
Expand Down
13 changes: 13 additions & 0 deletions src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -783,6 +783,19 @@ export function getValue(obj, key) {
return obj[key];
}

/**
* Get the key of an object for a given value
*/
export function getKeyByValue(obj, value) {
for (let prop in obj) {
if (obj.hasOwnProperty(prop)) {
if (obj[prop] === value) {
return prop;
}
}
}
}

export function getBidderCodes(adUnits = $$PREBID_GLOBAL$$.adUnits) {
// this could memoize adUnits
return adUnits.map(unit => unit.bids.map(bid => bid.bidder)
Expand Down
40 changes: 39 additions & 1 deletion test/spec/native_spec.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { expect } from 'chai';
import { fireNativeTrackers, getNativeTargeting, nativeBidIsValid } from 'src/native';
import { fireNativeTrackers, getNativeTargeting, nativeBidIsValid, getAssetMessage } from 'src/native';
import CONSTANTS from 'src/constants.json';
const utils = require('src/utils');

const bid = {
adId: '123',
native: {
title: 'Native Creative',
body: 'Cool description great stuff',
Expand Down Expand Up @@ -50,6 +51,22 @@ describe('native.js', function () {
expect(targeting[CONSTANTS.NATIVE_KEYS.clickUrl]).to.equal(bid.native.clickUrl);
});

it('sends placeholders for configured assets', function () {
const bidRequest = {
mediaTypes: {
native: {
body: { sendId: true },
clickUrl: { sendId: true },
}
}
};
const targeting = getNativeTargeting(bid, bidRequest);

expect(targeting[CONSTANTS.NATIVE_KEYS.title]).to.equal(bid.native.title);
expect(targeting[CONSTANTS.NATIVE_KEYS.body]).to.equal('hb_native_body:123');
expect(targeting[CONSTANTS.NATIVE_KEYS.clickUrl]).to.equal('hb_native_linkurl:123');
});

it('should only include native targeting keys with values', function () {
const targeting = getNativeTargeting(bidWithUndefinedFields);

Expand All @@ -72,6 +89,27 @@ describe('native.js', function () {
sinon.assert.calledOnce(triggerPixelStub);
sinon.assert.calledWith(triggerPixelStub, bid.native.clickTrackers[0]);
});

it('creates native asset message', function() {
const messageRequest = {
message: 'Prebid Native',
action: 'assetRequest',
adId: '123',
assets: ['hb_native_body', 'hb_native_linkurl'],
};

const message = getAssetMessage(messageRequest, bid);

expect(message.assets.length).to.equal(2);
expect(message.assets).to.deep.include({
key: 'body',
value: bid.native.body
});
expect(message.assets).to.deep.include({
key: 'clickUrl',
value: bid.native.clickUrl
});
});
});

describe('validate native', function () {
Expand Down

0 comments on commit 99977a9

Please sign in to comment.