Skip to content

Commit

Permalink
Add Geoedge RTD provider submodule (#5869)
Browse files Browse the repository at this point in the history
* Add Geoedge RTD provider submodule

* Add Geoedge RTD provider submodule accroding to RTD phase 3
* Add tests
* Add docs
* Add integration example
* Add as child module of RTD for easier builds

* Update RTD submodule interface

See https://docs.prebid.org/dev-docs/add-rtd-submodule.html

* Update tests

* Update integration example

remove unnecessary param

* Update docs

* Update RTD submodule provider

* Remove getConfig
* Get params from init
* Use beforeInit

* Update docs

Extend and document the wap param

* Update tests

* Remove unused config module

* Update integreation example

Relevant opening and inline comments

* Update Geoedge RTD submodule provider

* Hardcode HTTPS scheme
* Rename to "donePreload" for clarity
* Use regex to replace macros instead of loop

* Update tests

Preload request scheme is now always HTTPS

* Remove integration example HTML page

As for @Fawke request at #5869 (comment)

Co-authored-by: daniel manan <mmndaniel@gmail.com>
Co-authored-by: bretg <bgorsline@gmail.com>
  • Loading branch information
3 people authored Nov 24, 2020
1 parent 015c48b commit 1f24ee4
Show file tree
Hide file tree
Showing 4 changed files with 393 additions and 1 deletion.
3 changes: 2 additions & 1 deletion modules/.submodules.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"browsiRtdProvider",
"haloRtdProvider",
"jwplayerRtdProvider",
"reconciliationRtdProvider"
"reconciliationRtdProvider",
"geoedgeRtdProvider"
]
}
213 changes: 213 additions & 0 deletions modules/geoedgeRtdProvider.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
/**
* This module adds geoedge provider to the real time data module
* The {@link module:modules/realTimeData} module is required
* The module will fetch creative wrapper from geoedge server
* The module will place geoedge RUM client on bid responses markup
* @module modules/geoedgeProvider
* @requires module:modules/realTimeData
*/

/**
* @typedef {Object} ModuleParams
* @property {string} key
* @property {?Object} bidders
* @property {?boolean} wap
* @property {?string} keyName
*/

import { submodule } from '../src/hook.js';
import { ajax } from '../src/ajax.js';
import { generateUUID, insertElement, isEmpty, logError } from '../src/utils.js';

/** @type {string} */
const SUBMODULE_NAME = 'geoedge';
/** @type {string} */
export const WRAPPER_URL = 'https://wrappers.geoedge.be/wrapper.html';
/** @type {string} */
/* eslint-disable no-template-curly-in-string */
export const HTML_PLACEHOLDER = '${creative}';
/** @type {string} */
const PV_ID = generateUUID();
/** @type {string} */
const HOST_NAME = 'https://rumcdn.geoedge.be';
/** @type {string} */
const FILE_NAME = 'grumi.js';
/** @type {function} */
export let getClientUrl = (key) => `${HOST_NAME}/${key}/${FILE_NAME}`;
/** @type {string} */
export let wrapper
/** @type {boolean} */;
let wrapperReady;
/** @type {boolean} */;
let preloaded;

/**
* fetches the creative wrapper
* @param {function} sucess - success callback
*/
export function fetchWrapper(success) {
if (wrapperReady) {
return success(wrapper);
}
ajax(WRAPPER_URL, success);
}

/**
* sets the wrapper and calls preload client
* @param {string} responseText
*/
export function setWrapper(responseText) {
wrapperReady = true;
wrapper = responseText;
}

/**
* preloads the client
* @param {string} key
*/
export function preloadClient(key) {
let link = document.createElement('link');
link.rel = 'preload';
link.as = 'script';
link.href = getClientUrl(key);
link.onload = () => { preloaded = true };
insertElement(link);
}

/**
* creates identity function for string replace without special replacement patterns
* @param {string} str
* @return {function}
*/
function replacer(str) {
return function () {
return str;
}
}

export function wrapHtml(wrapper, html) {
return wrapper.replace(HTML_PLACEHOLDER, replacer(html));
}

/**
* generate macros dictionary from bid response
* @param {Object} bid
* @param {string} key
* @return {Object}
*/
function getMacros(bid, key) {
return {
'${key}': key,
'%%ADUNIT%%': bid.adUnitCode,
'%%WIDTH%%': bid.width,
'%%HEIGHT%%': bid.height,
'%%PATTERN:hb_adid%%': bid.adId,
'%%PATTERN:hb_bidder%%': bid.bidderCode,
'%_isHb!': true,
'%_hbcid!': bid.creativeId || '',
'%%PATTERN:hb_pb%%': bid.pbHg,
'%%SITE%%': location.hostname,
'%_pimp%': PV_ID
};
}

/**
* replace macro placeholders in a string with values from a dictionary
* @param {string} wrapper
* @param {Object} macros
* @return {string}
*/
function replaceMacros(wrapper, macros) {
var re = new RegExp('\\' + Object.keys(macros).join('|'), 'gi');

return wrapper.replace(re, function(matched) {
return macros[matched];
});
}

/**
* build final creative html with creative wrapper
* @param {Object} bid
* @param {string} wrapper
* @param {string} html
* @return {string}
*/
function buildHtml(bid, wrapper, html, key) {
let macros = getMacros(bid, key);
wrapper = replaceMacros(wrapper, macros);
return wrapHtml(wrapper, html);
}

/**
* muatates the bid ad property
* @param {Object} bid
* @param {string} ad
*/
function mutateBid(bid, ad) {
bid.ad = ad;
}

/**
* wraps a bid object with the creative wrapper
* @param {Object} bid
* @param {string} key
*/
export function wrapBidResponse(bid, key) {
let wrapped = buildHtml(bid, wrapper, bid.ad, key);
mutateBid(bid, wrapped);
}

/**
* checks if bidder's bids should be monitored
* @param {string} bidder
* @return {boolean}
*/
function isSupportedBidder(bidder, paramsBidders) {
return isEmpty(paramsBidders) || paramsBidders[bidder] === true;
}

/**
* checks if bid should be monitored
* @param {Object} bid
* @return {boolean}
*/
function shouldWrap(bid, params) {
let supportedBidder = isSupportedBidder(bid.bidderCode, params.bidders);
let donePreload = params.wap ? preloaded : true;
return wrapperReady && supportedBidder && donePreload;
}

function conditionallyWrap(bidResponse, config, userConsent) {
let params = config.params;
if (shouldWrap(bidResponse, params)) {
wrapBidResponse(bidResponse, params.key);
}
}

function init(config, userConsent) {
let params = config.params;
if (!params || !params.key) {
logError('missing key for geoedge RTD module provider');
return false;
}
preloadClient(params.key);
return true;
}

/** @type {RtdSubmodule} */
export const geoedgeSubmodule = {
/**
* used to link submodule with realTimeData
* @type {string}
*/
name: SUBMODULE_NAME,
init,
onBidResponseEvent: conditionallyWrap
};

export function beforeInit() {
fetchWrapper(setWrapper);
submodule('realTimeData', geoedgeSubmodule);
}

beforeInit();
67 changes: 67 additions & 0 deletions modules/geoedgeRtdProvider.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
## Overview

Module Name: Geoedge Rtd provider
Module Type: Rtd Provider
Maintainer: guy.books@geoedge.com

The Geoedge Realtime module let pusblishers to block bad ads such as automatic redirects, malware, offensive creatives and landing pages.
To use this module, you'll need to work with [Geoedge](https://www.geoedge.com/publishers-real-time-protection/) to get an account and cutomer key.

## Integration

1) Build the geoedge RTD module into the Prebid.js package with:

```
gulp build --modules=geoedgeRtdProvider,...
```

2) Use `setConfig` to instruct Prebid.js to initilize the geoedge module, as specified below.

## Configuration

This module is configured as part of the `realTimeData.dataProviders` object:

```javascript
pbjs.setConfig({
realTimeData: {
dataProviders: [{
name: 'geoedge',
params: {
key: '123123',
bidders: {
'bidderA': true, // monitor bids form this bidder
'bidderB': false // do not monitor bids form this bidder.
},
wap: true
}
}]
}
});
```

Parameters details:

{: .table .table-bordered .table-striped }
|Name |Type |Description |Notes |
| :------------ | :------------ | :------------ |:------------ |
|name | String | Real time data module name |Required, always 'geoedge' |
|params | Object | | |
|params.key | String | Customer key |Required, contact Geoedge to get your key |
|params.bidders | Object | Bidders to monitor |Optional, list of bidder to include / exclude from monitoring. Omitting this will monitor bids from all bidders. |
|params.wap |Boolean |Wrap after preload |Optional, defaults to `false`. Set to `true` if you want to monitor only after the module has preloaded the monitoring client. |

## Example

To view an integration example:

1) in your cli run:

```
gulp serve --modules=appnexusBidAdapter,geoedgeRtdProvider
```

2) in your browser, navigate to:

```
http://localhost:9999/integrationExamples/gpt/geoedgeRtdProvider_example.html
```
Loading

0 comments on commit 1f24ee4

Please sign in to comment.