From 75689e0175afa55b26fc520eed5e67e0b7c462a0 Mon Sep 17 00:00:00 2001 From: cosminser Date: Fri, 17 Mar 2023 09:57:00 +0200 Subject: [PATCH 1/2] added connatixBidAdapter --- modules/connatixBidAdapter.js | 189 ++++++++++++++++++++++++++++++++++ 1 file changed, 189 insertions(+) create mode 100644 modules/connatixBidAdapter.js diff --git a/modules/connatixBidAdapter.js b/modules/connatixBidAdapter.js new file mode 100644 index 00000000000..b15b424219b --- /dev/null +++ b/modules/connatixBidAdapter.js @@ -0,0 +1,189 @@ +import { + deepAccess, + isFn, + logError, + logMessage +} from '../src/utils.js'; + +import { + registerBidder +} from '../src/adapters/bidderFactory.js'; +import { + config +} from '../src/config.js'; +import { + BANNER, +} from '../src/mediaTypes.js'; + +const BIDDER_CODE = 'connatix'; +const AD_URL = 'https://placeholder.com/pbjs'; +const SYNC_URL = 'https://placeholder.com/sync'; +const DEFAULT_MAX_TTL = '3600'; +const DEFAULT_CURRENCY = 'USD'; + +/* Get the bid floor value from the bid object, + either using the getFloor function or by accessing the 'params.bidfloor' property. + If the bid floor cannot be determined, return 0 as a fallback value. +*/ +function getBidFloor(bid) { + if (!isFn(bid.getFloor)) { + return deepAccess(bid, 'params.bidfloor', 0); + } + + try { + const bidFloor = bid.getFloor({ + currency: DEFAULT_CURRENCY, + mediaType: '*', + size: '*', + }); + return bidFloor.floor; + } catch (err) { + logError(err); + return 0; + } +} + +/* Wrap the provided bid, playerId, customerId, and scriptId in an HTML string + that includes the Connatix player script and related data. + This HTML string will be used as the ad content. + */ +function wrapAd(bid, playerId, customerId, scriptId, isInApp) { + const scriptSrc = isInApp ? `'//cd.connatix.com/connatix.player.omid.js?cid=${customerId}'` : `'//cd.connatix.com/connatix.player.js?cid=${customerId}'`; + return ` + + + + + + + + + + + `; +} + +export const spec = { + code: BIDDER_CODE, + gvlid: 143, + supportedMediaTypes: [BANNER], + + /* Check if a bid request is valid by verifying if the bidId, params, + and placementId properties are present, + and if the mediaTypes object contains a BANNER object with a sizes property. */ + isBidRequestValid: (bid = {}) => { + const { + params, + bidId, + mediaTypes + } = bid; + if (!(bidId && params && params.placementId)) { + return false; + }; + + return Boolean(mediaTypes[BANNER] && mediaTypes[BANNER].sizes); + }, + + /* Build the request payload by processing valid bid requests and extracting the necessary information. + Determine the host and page from the bidderRequest's refferUrl, and include ccpa and gdpr consents. + Return an object containing the request method, url, and the constructed payload. */ + buildRequests: (validBidRequests = [], bidderRequest = {}) => { + const ccpa = bidderRequest.uspConsent || undefined; + const gdpr = bidderRequest.gdprConsent || undefined; + + let refferLocation; + try { + refferLocation = bidderRequest.refferUrl && new URL(bidderRequest.refferUrl); + } catch (e) { + logMessage(e); + } + + const host = refferLocation ? refferLocation.host : window.top.location.host; + const page = refferLocation ? refferLocation.pathname : window.top.location.pathname; + + const bidRequests = validBidRequests.map(bid => { + const { + bidId, + mediaTypes, + params, + sizes + } = bid; + return { + bidId, + sizes, + mediaTypes, + placementId: params.placementId, + floor: getBidFloor(bid), + }; + }); + + const requestPayload = { + host, + page, + bidRequests, + ccpa, + gdpr, + } + + return { + method: 'POST', + url: AD_URL, + data: requestPayload + }; + }, + + /* Interpret the server response and create an array of bid responses by extracting and formatting + relevant information such as requestId, cpm, width, height, creativeId, + and ad content (wrapped using the wrapAd function). */ + interpretResponse: (serverResponse) => { + const bidResponses = serverResponse.body[0].bids.map(bidResponse => { + return { + requestId: bidResponse.bidId, + cpm: bidResponse.cpm, + width: bidResponse.width, + height: bidResponse.height, + creativeId: bidResponse.creativeId, + netRevenue: true, + ttl: bidResponse.ttl || DEFAULT_MAX_TTL, + referrer: bidResponse.referrer, + ad: wrapAd(bidResponse.ad, bidResponse.width, bidResponse.height), + }; + }); + + return bidResponses; + }, + + /* Determine the user sync type (either 'iframe' or 'image') based on syncOptions. + Construct the sync URL by appending required query parameters such as gdpr, ccpa, and coppa consents. + Return an array containing an object with the sync type and the constructed URL. */ + getUserSyncs: (syncOptions, serverResponses, gdprConsent, uspConsent) => { + let syncType = syncOptions.iframeEnabled ? 'iframe' : 'image'; + let syncUrl = SYNC_URL + `/${syncType}?pbjs=1`; + if (gdprConsent && gdprConsent.consentString) { + if (typeof gdprConsent.gdprApplies === 'boolean') { + syncUrl += `&gdpr=${Number(gdprConsent.gdprApplies)}&gdpr_consent=${gdprConsent.consentString}`; + } else { + syncUrl += `&gdpr=0&gdpr_consent=${gdprConsent.consentString}`; + } + } + if (uspConsent && uspConsent.consentString) { + syncUrl += `&ccpa_consent=${uspConsent.consentString}`; + } + + const coppa = config.getConfig('coppa') ? 1 : 0; + syncUrl += `&coppa=${coppa}`; + + return [{ + type: syncType, + url: syncUrl + }]; + } + +}; + +registerBidder(spec); From 1d2bbef7a2f7a3d0acc3a604d1c69075102b2890 Mon Sep 17 00:00:00 2001 From: cosminser Date: Fri, 17 Mar 2023 13:31:20 +0200 Subject: [PATCH 2/2] added todo --- modules/connatixBidAdapter.js | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/connatixBidAdapter.js b/modules/connatixBidAdapter.js index b15b424219b..5a1e71258e0 100644 --- a/modules/connatixBidAdapter.js +++ b/modules/connatixBidAdapter.js @@ -148,6 +148,7 @@ export const spec = { width: bidResponse.width, height: bidResponse.height, creativeId: bidResponse.creativeId, + // TODO: check if we'll get netRevenue from the server netRevenue: true, ttl: bidResponse.ttl || DEFAULT_MAX_TTL, referrer: bidResponse.referrer,