From d11851e5a3469859f3c98209f0d5dcfd2cd79012 Mon Sep 17 00:00:00 2001 From: relaido <63339139+relaido@users.noreply.github.com> Date: Tue, 23 Apr 2024 22:56:27 +0900 Subject: [PATCH] Relaido Bid Adapter: add pagekvt to request and add ogUrl to params (#11318) * add relaido adapter * remove event listener * fixed UserSyncs and e.data * fix conflicts * Change the initial value of userIdAsEids to an empty array * add pagekvt to request * add ogUrl to params --------- Co-authored-by: ishigami_shingo Co-authored-by: cmertv-sishigami Co-authored-by: t_bun Co-authored-by: n.maeura --- modules/relaidoBidAdapter.js | 79 ++++++++++++++++++--- test/spec/modules/relaidoBidAdapter_spec.js | 62 ++++++++++++++++ 2 files changed, 132 insertions(+), 9 deletions(-) diff --git a/modules/relaidoBidAdapter.js b/modules/relaidoBidAdapter.js index 751e8fa442c..a180d04cc71 100644 --- a/modules/relaidoBidAdapter.js +++ b/modules/relaidoBidAdapter.js @@ -7,17 +7,19 @@ import { isArray, isNumber, parseSizesInput, - getBidIdParameter + getBidIdParameter, + isGptPubadsDefined } from '../src/utils.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { BANNER, VIDEO } from '../src/mediaTypes.js'; import { Renderer } from '../src/Renderer.js'; import { getStorageManager } from '../src/storageManager.js'; import sha1 from 'crypto-js/sha1'; +import { isSlotMatchingAdUnitCode } from '../libraries/gptUtils/gptUtils.js'; const BIDDER_CODE = 'relaido'; const BIDDER_DOMAIN = 'api.relaido.jp'; -const ADAPTER_VERSION = '1.1.0'; +const ADAPTER_VERSION = '1.2.0'; const DEFAULT_TTL = 300; const UUID_KEY = 'relaido_uuid'; @@ -47,6 +49,7 @@ function buildRequests(validBidRequests, bidderRequest) { let bidDomain = null; let bidder = null; let count = null; + let isOgUrlOption = false; for (let i = 0; i < validBidRequests.length; i++) { const bidRequest = validBidRequests[i]; @@ -92,6 +95,10 @@ function buildRequests(validBidRequests, bidderRequest) { count = bidRequest.bidRequestsCount; } + if (getBidIdParameter('ogUrl', bidRequest.params)) { + isOgUrlOption = true; + } + bids.push({ bid_id: bidRequest.bidId, placement_id: getBidIdParameter('placementId', bidRequest.params), @@ -105,10 +112,13 @@ function buildRequests(validBidRequests, bidderRequest) { height: height, banner_sizes: getBannerSizes(bidRequest), media_type: mediaType, - userIdAsEids: bidRequest.userIdAsEids || {}, + userIdAsEids: bidRequest.userIdAsEids || [], + pagekvt: getTargeting(bidRequest), }); } + const canonicalUrl = getCanonicalUrl(bidderRequest.refererInfo?.canonicalUrl, isOgUrlOption); + const data = JSON.stringify({ version: ADAPTER_VERSION, bids: bids, @@ -118,8 +128,8 @@ function buildRequests(validBidRequests, bidderRequest) { uuid: getUuid(), pv: '$prebid.version$', imuid: imuid, - canonical_url: bidderRequest.refererInfo?.canonicalUrl || null, - canonical_url_hash: getCanonicalUrlHash(bidderRequest.refererInfo), + canonical_url: canonicalUrl, + canonical_url_hash: getCanonicalUrlHash(canonicalUrl), ref: bidderRequest.refererInfo.page }); @@ -294,12 +304,25 @@ function getUuid() { return newId; } -function getCanonicalUrlHash(refererInfo) { - const canonicalUrl = refererInfo.canonicalUrl || null; +function getOgUrl() { + try { + const ogURLElement = window.top.document.querySelector('meta[property="og:url"]'); + return ogURLElement ? ogURLElement.content : null; + } catch (e) { + const ogURLElement = document.querySelector('meta[property="og:url"]'); + return ogURLElement ? ogURLElement.content : null; + } +} + +function getCanonicalUrl(canonicalUrl, isOgUrlOption) { if (!canonicalUrl) { - return null; + return (isOgUrlOption) ? getOgUrl() : null; } - return sha1(canonicalUrl).toString(); + return canonicalUrl; +} + +function getCanonicalUrlHash(canonicalUrl) { + return (canonicalUrl) ? sha1(canonicalUrl).toString() : null; } function hasBannerMediaType(bid) { @@ -349,6 +372,44 @@ function getBannerSizes(bidRequest) { return parseSizesInput(sizes).join(','); } +function getTargeting(bidRequest) { + const targetings = {}; + const pubads = getPubads(); + if (pubads) { + const keys = pubads.getTargetingKeys(); + for (const key of keys) { + const values = pubads.getTargeting(key); + targetings[key] = values; + } + } + const adUnitSlot = getAdUnit(bidRequest.adUnitCode); + if (adUnitSlot) { + const keys = adUnitSlot.getTargetingKeys(); + for (const key of keys) { + const values = adUnitSlot.getTargeting(key); + targetings[key] = values; + } + } + return targetings; +} + +function getPubads() { + return (isGptPubadsDefined()) ? window.googletag.pubads() : null; +} + +function getAdUnit(adUnitCode) { + if (isGptPubadsDefined()) { + const adSlots = window.googletag.pubads().getSlots(); + const isMatchingAdSlot = isSlotMatchingAdUnitCode(adUnitCode); + for (let i = 0; i < adSlots.length; i++) { + if (isMatchingAdSlot(adSlots[i])) { + return adSlots[i]; + } + } + } + return null; +} + export const spec = { code: BIDDER_CODE, supportedMediaTypes: [BANNER, VIDEO], diff --git a/test/spec/modules/relaidoBidAdapter_spec.js b/test/spec/modules/relaidoBidAdapter_spec.js index f0d019913e8..4a07c84a494 100644 --- a/test/spec/modules/relaidoBidAdapter_spec.js +++ b/test/spec/modules/relaidoBidAdapter_spec.js @@ -3,6 +3,7 @@ import {spec} from 'modules/relaidoBidAdapter.js'; import * as utils from 'src/utils.js'; import {VIDEO} from 'src/mediaTypes.js'; import {getCoreStorageManager} from '../../../src/storageManager.js'; +import * as mockGpt from '../integration/faker/googletag.js'; const UUID_KEY = 'relaido_uuid'; const relaido_uuid = 'hogehoge'; @@ -15,14 +16,18 @@ describe('RelaidoAdapter', function () { let serverRequest; let generateUUIDStub; let triggerPixelStub; + let sandbox; + before(() => { const storage = getCoreStorageManager(); storage.setCookie(UUID_KEY, relaido_uuid); }); beforeEach(function () { + mockGpt.disable(); generateUUIDStub = sinon.stub(utils, 'generateUUID').returns(relaido_uuid); triggerPixelStub = sinon.stub(utils, 'triggerPixel'); + sandbox = sinon.sandbox.create(); bidRequest = { bidder: 'relaido', params: { @@ -115,6 +120,7 @@ describe('RelaidoAdapter', function () { afterEach(() => { generateUUIDStub.restore(); triggerPixelStub.restore(); + sandbox.restore(); }); describe('spec.isBidRequestValid', function () { @@ -251,8 +257,10 @@ describe('RelaidoAdapter', function () { expect(request.bid_id).to.equal(bidRequest.bidId); expect(request.transaction_id).to.equal(bidRequest.ortb2Imp.ext.tid); expect(request.media_type).to.equal('video'); + expect(request.pagekvt).to.deep.equal({}); expect(data.uuid).to.equal(relaido_uuid); expect(data.pv).to.equal('$prebid.version$'); + expect(request.userIdAsEids).to.be.an('array'); }); it('should build bid requests by banner', function () { @@ -335,6 +343,60 @@ describe('RelaidoAdapter', function () { expect(data.bids[0].userIdAsEids).to.have.lengthOf(1); expect(data.bids[0].userIdAsEids[0].source).to.equal('hogehoge.com'); }); + + it('should get pagekvt', function () { + mockGpt.enable(); + window.googletag.pubads().clearTargeting(); + window.googletag.pubads().setTargeting('testkey', ['testvalue']); + bidRequest.adUnitCode = 'test-adunit-code-1'; + window.googletag.pubads().setSlots([mockGpt.makeSlot({ code: bidRequest.adUnitCode })]); + const bidRequests = spec.buildRequests([bidRequest], bidderRequest); + const data = JSON.parse(bidRequests.data); + expect(data.bids).to.have.lengthOf(1); + const request = data.bids[0]; + expect(request.pagekvt).to.deep.equal({testkey: ['testvalue']}); + }); + + it('should get canonicalUrl (ogUrl:true)', function () { + bidRequest.params.ogUrl = true; + bidderRequest.refererInfo.canonicalUrl = null; + let documentStub = sandbox.stub(window.top.document, 'querySelector'); + documentStub.withArgs('meta[property="og:url"]').returns({ + content: 'http://localhost:9999/fb-test' + }); + const bidRequests = spec.buildRequests([bidRequest], bidderRequest); + const data = JSON.parse(bidRequests.data); + expect(data.bids).to.have.lengthOf(1); + expect(data.canonical_url).to.equal('http://localhost:9999/fb-test'); + expect(data.canonical_url_hash).to.equal('cd106829f866d60ee4ed43c6e2a5d0a5212ffc97'); + }); + + it('should not get canonicalUrl (ogUrl:false)', function () { + bidRequest.params.ogUrl = false; + bidderRequest.refererInfo.canonicalUrl = null; + let documentStub = sandbox.stub(window.top.document, 'querySelector'); + documentStub.withArgs('meta[property="og:url"]').returns({ + content: 'http://localhost:9999/fb-test' + }); + const bidRequests = spec.buildRequests([bidRequest], bidderRequest); + const data = JSON.parse(bidRequests.data); + expect(data.bids).to.have.lengthOf(1); + expect(data.canonical_url).to.be.null; + expect(data.canonical_url_hash).to.be.null; + }); + + it('should not get canonicalUrl (ogUrl:nothing)', function () { + bidderRequest.refererInfo.canonicalUrl = null; + let documentStub = sandbox.stub(window.top.document, 'querySelector'); + documentStub.withArgs('meta[property="og:url"]').returns({ + content: 'http://localhost:9999/fb-test' + }); + const bidRequests = spec.buildRequests([bidRequest], bidderRequest); + const data = JSON.parse(bidRequests.data); + expect(data.bids).to.have.lengthOf(1); + expect(data.canonical_url).to.be.null; + expect(data.canonical_url_hash).to.be.null; + }); }); describe('spec.interpretResponse', function () {