Skip to content

Commit

Permalink
Blue Bid Adapter : initial release (#12513)
Browse files Browse the repository at this point in the history
* add blue

* uncommited stuff

* uncommited stuff

* uncommited stuff

* less duplicated code

* less duplicated code

* less duplicated code

* less duplicated code

* less duplicated code

* blue adapter

* blue adapter

* blue adapter

* blue adapter

* blue adapter

* blue adapter

* blue adapter

* blue adapter

* blue adapter

* blue adapter

* blue adapter

* add floor module support

* add floor module support

* add floor module support

* add floor module support

* add floor module support

* only import what we need

* Prebib

---------

Co-authored-by: Tulio Duarte <[email protected]>
  • Loading branch information
maqtulio and tulio-bms authored Jan 13, 2025
1 parent 7a210da commit 16d892e
Show file tree
Hide file tree
Showing 3 changed files with 241 additions and 0 deletions.
122 changes: 122 additions & 0 deletions modules/blueBidAdapter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import { ortbConverter } from '../libraries/ortbConverter/converter.js';
import { registerBidder } from '../src/adapters/bidderFactory.js';
import { BANNER } from '../src/mediaTypes.js';
import { getStorageManager } from '../src/storageManager.js';
import { deepSetValue, isFn, isPlainObject } from '../src/utils.js';

const BIDDER_CODE = 'blue';
const ENDPOINT_URL = 'https://bidder-us-east-1.getblue.io/engine/?src=prebid';
const GVLID = 620; // GVLID for your bidder
const COOKIE_NAME = 'ckid'; // Cookie name for identifying users
const CURRENCY = 'USD'; // Currency used in bid floors

export const storage = getStorageManager({ bidderCode: BIDDER_CODE });

const converter = ortbConverter({
context: {
netRevenue: true, // Default netRevenue setting
ttl: 100, // Default time-to-live for bid responses
},
imp,
request,
});

function request(buildRequest, imps, bidderRequest, context) {
let request = buildRequest(imps, bidderRequest, context);
deepSetValue(request, 'site.publisher.id', context.publisherId);
return request;
}

function imp(buildImp, bidRequest, context) {
const imp = buildImp(bidRequest, context);
const floor = getBidFloor(bidRequest);
if (floor) {
imp.bidfloor = floor;
imp.bidfloorcur = CURRENCY;
}
return imp;
}

function getBidFloor(bid) {
if (isFn(bid.getFloor)) {
let floor = bid.getFloor({
currency: CURRENCY,
mediaType: BANNER,
size: '*',
});
if (
isPlainObject(floor) &&
!isNaN(floor.floor) &&
floor.currency === CURRENCY
) {
return floor.floor;
}
}
return null;
}

export const spec = {
code: BIDDER_CODE,
gvlid: GVLID,
supportedMediaTypes: [BANNER], // Supported ad types

// Validate bid request
isBidRequestValid: function (bid) {
return !!bid.params.placementId && !!bid.params.publisherId;
},

// Build OpenRTB requests using `ortbConverter`
buildRequests: function (validBidRequests, bidderRequest) {
const context = {
publisherId: validBidRequests.find(
(bidRequest) => bidRequest.params?.publisherId
)?.params.publisherId,
};

const ortbRequest = converter.toORTB({
bidRequests: validBidRequests,
bidderRequest,
context,
});

// Add GVLID and cookie ID to the request
ortbRequest.ext = ortbRequest.ext || {};
deepSetValue(ortbRequest, 'ext.gvlid', GVLID);

// Include user cookie if available
const ckid = storage.getDataFromLocalStorage('blueID') || storage.getCookie(COOKIE_NAME) || null;
if (ckid) {
deepSetValue(ortbRequest, 'user.ext.buyerid', ckid);
}

return {
method: 'POST',
url: ENDPOINT_URL,
data: JSON.stringify(ortbRequest),
options: {
contentType: 'text/plain',
},
};
},

// Interpret OpenRTB responses using `ortbConverter`
interpretResponse: function (serverResponse, request) {
const ortbResponse = serverResponse.body;

// Parse the OpenRTB response into Prebid bid responses
const prebidResponses = converter.fromORTB({
response: ortbResponse,
request: request.data,
}).bids;

// Example: Modify bid responses if needed
prebidResponses.forEach((bid) => {
bid.meta = bid.meta || {};
bid.meta.adapterVersion = '1.0.0';
});

return prebidResponses;
},
};

registerBidder(spec);
28 changes: 28 additions & 0 deletions modules/blueBidAdapter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Overview

Module Name: Blue Bidder Adapter
Module Type: Bidder Adapter
Maintainer: [email protected]

# Description

Module that connects to Blue's demand sources.

# Test Parameters
```
var adUnits = [
{
code: 'banner-ad-div',
sizes: [[300, 250], [728, 90]],
bids: [
{
bidder: 'blue',
params: {
publisherId: "xpto",
placementId: "xpto",
}
}
]
}
];
```
91 changes: 91 additions & 0 deletions test/spec/modules/blueBidAdapter_spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { expect } from 'chai';
import sinon from 'sinon';
import { spec, storage } from 'modules/blueBidAdapter.js';

const BIDDER_CODE = 'blue';
const ENDPOINT_URL = 'https://bidder-us-east-1.getblue.io/engine/?src=prebid';
const GVLID = 620;
const COOKIE_NAME = 'ckid';
const CURRENCY = 'USD';

describe('blueBidAdapter:', function () {
let sandbox;

beforeEach(function () {
sandbox = sinon.createSandbox();
});

afterEach(function () {
sandbox.restore();
});

describe('isBidRequestValid:', function () {
it('should return true for valid bid requests', function () {
const validBid = {
params: {
placementId: '12345',
publisherId: '67890',
},
};
expect(spec.isBidRequestValid(validBid)).to.be.true;
});

it('should return false for invalid bid requests', function () {
const invalidBid = {
params: {
placementId: '12345',
},
};
expect(spec.isBidRequestValid(invalidBid)).to.be.false;
});
});

describe('buildRequests:', function () {
let validBidRequests;
let bidderRequest;

beforeEach(function () {
validBidRequests = [
{
bidId: 'bid1',
params: {
placementId: '12345',
publisherId: '67890',
},
getFloor: () => ({ currency: CURRENCY, floor: 1.5 }),
},
];

bidderRequest = {
refererInfo: {
page: 'https://example.com',
},
};

sandbox.stub(storage, 'getDataFromLocalStorage').returns('testBuyerId');
});

it('should build a valid OpenRTB request', function () {
const request = spec.buildRequests(validBidRequests, bidderRequest);

expect(request.method).to.equal('POST');
expect(request.url).to.equal(ENDPOINT_URL);
expect(request.options.contentType).to.equal('text/plain');

const ortbRequest = JSON.parse(request.data);
expect(ortbRequest.ext.gvlid).to.equal(GVLID);
expect(ortbRequest.user.ext.buyerid).to.equal('testBuyerId');
expect(ortbRequest.imp[0].bidfloor).to.equal(1.5);
expect(ortbRequest.imp[0].bidfloorcur).to.equal(CURRENCY);
});

it('should omit bidfloor if getFloor is not implemented', function () {
validBidRequests[0].getFloor = undefined;

const request = spec.buildRequests(validBidRequests, bidderRequest);
const ortbRequest = JSON.parse(request.data);

expect(ortbRequest.imp[0].bidfloor).to.be.undefined;
});
});
});

0 comments on commit 16d892e

Please sign in to comment.