Skip to content

Commit

Permalink
Pubmatic: add dctr and pmzoneid params (#1320)
Browse files Browse the repository at this point in the history
  • Loading branch information
nickluck8 authored Jun 17, 2021
1 parent 02e44d0 commit 5c74390
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 44 deletions.
46 changes: 24 additions & 22 deletions src/main/java/org/prebid/server/bidder/pubmatic/PubmaticBidder.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.iab.openrtb.request.App;
import com.iab.openrtb.request.Banner;
Expand Down Expand Up @@ -32,13 +33,11 @@
import org.prebid.server.proto.openrtb.ext.ExtPrebid;
import org.prebid.server.proto.openrtb.ext.request.ExtRequest;
import org.prebid.server.proto.openrtb.ext.request.pubmatic.ExtImpPubmatic;
import org.prebid.server.proto.openrtb.ext.request.pubmatic.ExtImpPubmaticKeyVal;
import org.prebid.server.proto.openrtb.ext.response.BidType;
import org.prebid.server.proto.openrtb.ext.response.ExtBidPrebid;
import org.prebid.server.proto.openrtb.ext.response.ExtBidPrebidVideo;
import org.prebid.server.util.HttpUtil;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
Expand All @@ -51,6 +50,9 @@ public class PubmaticBidder implements Bidder<BidRequest> {

private static final Logger logger = LoggerFactory.getLogger(PubmaticBidder.class);
private static final String PREBID = "prebid";
private static final String DCTR_KEY_NAME = "key_val";
private static final String PM_ZONE_ID_KEY_NAME = "pmZoneId";
private static final String PM_ZONE_ID_OLD_KEY_NAME = "pmZoneID";
private static final TypeReference<ExtPrebid<?, ExtImpPubmatic>> PUBMATIC_EXT_TYPE_REFERENCE =
new TypeReference<ExtPrebid<?, ExtImpPubmatic>>() {
};
Expand Down Expand Up @@ -163,29 +165,33 @@ private Imp modifyImp(Imp imp, ExtImpPubmatic extImpPubmatic) throws PreBidExcep
}

if (CollectionUtils.isNotEmpty(extImpPubmatic.getKeywords())) {
modifiedImp.ext(makeKeywords(extImpPubmatic.getKeywords()));
modifiedImp.ext(makeKeywords(extImpPubmatic));
} else {
modifiedImp.ext(null);
}
return modifiedImp.build();
}

private ObjectNode makeKeywords(List<ExtImpPubmaticKeyVal> keywords) {
final List<String> eachKv = new ArrayList<>();
for (ExtImpPubmaticKeyVal keyVal : keywords) {
if (CollectionUtils.isEmpty(keyVal.getValue())) {
logger.error(String.format("No values present for key = %s", keyVal.getKey()));
} else {
eachKv.add(String.format("\"%s\":\"%s\"", keyVal.getKey(),
String.join(",", keyVal.getValue())));
private ObjectNode makeKeywords(ExtImpPubmatic extImpPubmatic) {
final ObjectNode keywordsNode = mapper.mapper().createObjectNode();
extImpPubmatic.getKeywords().forEach(keyword -> {
if (CollectionUtils.isEmpty(keyword.getValue())) {
logger.error(String.format("No values present for key = %s", keyword.getValue()));
return;
}
keywordsNode.put(keyword.getKey(), String.join(",", keyword.getValue()));
});
final JsonNode pmZoneIdKeyWords = keywordsNode.remove(PM_ZONE_ID_OLD_KEY_NAME);
if (StringUtils.isNotEmpty(extImpPubmatic.getPmzoneid())) {
keywordsNode.put(PM_ZONE_ID_KEY_NAME, extImpPubmatic.getPmzoneid());
} else if (pmZoneIdKeyWords != null) {
keywordsNode.set(PM_ZONE_ID_KEY_NAME, pmZoneIdKeyWords);
}
final String keywordsString = "{" + String.join(",", eachKv) + "}";
try {
return mapper.mapper().readValue(keywordsString, ObjectNode.class);
} catch (IOException e) {
throw new PreBidException(String.format("Failed to create keywords with error: %s", e.getMessage()), e);
if (StringUtils.isNotEmpty(extImpPubmatic.getDctr())) {
keywordsNode.put(DCTR_KEY_NAME, extImpPubmatic.getDctr());
}

return keywordsNode;
}

private HttpRequest<BidRequest> makeRequest(BidRequest bidRequest, List<Imp> imps,
Expand Down Expand Up @@ -230,9 +236,7 @@ private static void modifySite(String pubId, BidRequest bidRequest,
final Publisher modifiedPublisher = site.getPublisher().toBuilder().id(pubId).build();
bidRequestBuilder.site(site.toBuilder().publisher(modifiedPublisher).build());
} else {
bidRequestBuilder.site(site.toBuilder()
.publisher(Publisher.builder().id(pubId).build())
.build());
bidRequestBuilder.site(site.toBuilder().publisher(Publisher.builder().id(pubId).build()).build());
}
}

Expand All @@ -243,9 +247,7 @@ private static void modifyApp(String pubId, BidRequest bidRequest,
final Publisher modifiedPublisher = app.getPublisher().toBuilder().id(pubId).build();
bidRequestBuilder.app(app.toBuilder().publisher(modifiedPublisher).build());
} else {
bidRequestBuilder.app(app.toBuilder()
.publisher(Publisher.builder().id(pubId).build())
.build());
bidRequestBuilder.app(app.toBuilder().publisher(Publisher.builder().id(pubId).build()).build());
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,8 @@ public class ExtImpPubmatic {
ObjectNode wrapper;

List<ExtImpPubmaticKeyVal> keywords;

String dctr;

String pmzoneid;
}
8 changes: 8 additions & 0 deletions src/main/resources/static/bidder-params/pubmatic.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@
"type": "string",
"description": "An ID which identifies the ad slot"
},
"pmzoneid": {
"type": "string",
"description": "Comma separated zone id. Used im deal targeting & site section targeting. e.g drama,sport"
},
"dctr": {
"type": "string",
"description": "Deals Custom Targeting, pipe separated key-value pairs e.g key1=V1,V2,V3|key2=v1|key3=v3,v5"
},
"wrapper": {
"type": "object",
"description": "Specifies pubmatic openwrap configuration for a publisher",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,24 +161,6 @@ public void makeHttpRequestsShouldReturnErrorIfAdSlotHasInvalidHeight() {
assertThat(result.getValue()).isEmpty();
}

@Test
public void makeHttpRequestsShouldReturnErrorIfKeywordsAreInvalid() {
// given
final BidRequest bidRequest = givenBidRequest(
identity(),
extImpPubmaticBuilder -> extImpPubmaticBuilder
.keywords(singletonList(ExtImpPubmaticKeyVal.of("\"", singletonList("\"")))));

// when
final Result<List<HttpRequest<BidRequest>>> result = pubmaticBidder.makeHttpRequests(bidRequest);

// then
assertThat(result.getErrors()).hasSize(1);
assertThat(result.getErrors().get(0).getMessage())
.startsWith("Failed to create keywords with error: Unexpected character");
assertThat(result.getValue()).isEmpty();
}

@Test
public void makeHttpRequestsShouldReturnErrorIfWrapExtHasInvalidParams() {
// given
Expand Down Expand Up @@ -644,6 +626,70 @@ public void makeBidsShouldReturnBannerBidIfExtBidContainsIllegalBidType() throws
.containsOnly(BidderBid.of(Bid.builder().impid("123").ext(bidType).build(), banner, "USD"));
}

@Test
public void makeHttpRequestsShouldReplaceDctrIfPresent() {
// given
final BidRequest bidRequest = givenBidRequest(
identity(),
extImpPubmaticBuilder -> extImpPubmaticBuilder.dctr("dctr")
.keywords(singletonList(ExtImpPubmaticKeyVal.of("key_val", asList("value1", "value2")))));

// when
final Result<List<HttpRequest<BidRequest>>> result = pubmaticBidder.makeHttpRequests(bidRequest);

// then
final Map<String, String> expectedKeyWords = singletonMap("key_val", "dctr");
assertThat(result.getErrors()).isEmpty();
assertThat(result.getValue()).hasSize(1)
.extracting(HttpRequest::getPayload)
.flatExtracting(BidRequest::getImp)
.extracting(Imp::getExt)
.containsExactly(mapper.convertValue(expectedKeyWords, ObjectNode.class));
}

@Test
public void makeHttpRequestsShouldReplacePmZoneIdIfPresent() {
// given
final BidRequest bidRequest = givenBidRequest(
identity(),
extImpPubmaticBuilder -> extImpPubmaticBuilder.pmzoneid("pmzoneid")
.keywords(singletonList(ExtImpPubmaticKeyVal.of("pmZoneId", asList("value1", "value2")))));

// when
final Result<List<HttpRequest<BidRequest>>> result = pubmaticBidder.makeHttpRequests(bidRequest);

// then
final Map<String, String> expectedKeyWords = singletonMap("pmZoneId", "pmzoneid");
assertThat(result.getErrors()).isEmpty();
assertThat(result.getValue()).hasSize(1)
.extracting(HttpRequest::getPayload)
.flatExtracting(BidRequest::getImp)
.extracting(Imp::getExt)
.containsExactly(mapper.convertValue(expectedKeyWords, ObjectNode.class));
}

@Test
public void makeHttpRequestsShouldReplacePmZoneIDOldKeyNameWithNew() {
// given
final BidRequest bidRequest = givenBidRequest(
identity(),
extImpPubmaticBuilder -> extImpPubmaticBuilder
.keywords(singletonList(ExtImpPubmaticKeyVal.of("pmZoneID", asList("value1", "value2")))));

// when
final Result<List<HttpRequest<BidRequest>>> result = pubmaticBidder.makeHttpRequests(bidRequest);

// then

final Map<String, String> expectedKeyWords = singletonMap("pmZoneId", "value1,value2");
assertThat(result.getErrors()).isEmpty();
assertThat(result.getValue()).hasSize(1)
.extracting(HttpRequest::getPayload)
.flatExtracting(BidRequest::getImp)
.extracting(Imp::getExt)
.containsExactly(mapper.convertValue(expectedKeyWords, ObjectNode.class));
}

private static BidRequest givenBidRequest(
Function<BidRequest.BidRequestBuilder, BidRequest.BidRequestBuilder> bidRequestCustomizer,
Function<Imp.ImpBuilder, Imp.ImpBuilder> impCustomizer,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"publisherId": " publisherId ",
"keywords": [
{
"key": "pmZoneID",
"key": "pmZoneId",
"value": [
"Zone1",
"Zone2"
Expand Down Expand Up @@ -53,9 +53,11 @@
"pubmatic": {
"adSlot": "slot9@300x250:zzz",
"publisherId": "publisherId",
"pmzoneid": "drama,sport",
"dctr": "abBucket=4|adType=page|entity=|paidByCategory=|sku=|userLevel=free|platform=android|majorVersion=3.54|version=3.54.0|mobileApplication=true|showId=20166|show=Kisah Untuk Geri|genre=Drama|contentUrl=https://www.iflix.com/title/show/20166|rating=TV-MA|contentLanguage=id",
"keywords": [
{
"key": "pmZoneID",
"key": "pmZoneId",
"value": [
"Zone1",
"Zone2"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
},
"tagid": "slot9",
"ext": {
"pmZoneID": "Zone1,Zone2",
"pmZoneId": "Zone1,Zone2",
"preference": "sports,movies"
}
},
Expand All @@ -29,7 +29,8 @@
"h": 600
},
"ext": {
"pmZoneID": "Zone1,Zone2"
"pmZoneId": "drama,sport",
"key_val": "abBucket=4|adType=page|entity=|paidByCategory=|sku=|userLevel=free|platform=android|majorVersion=3.54|version=3.54.0|mobileApplication=true|showId=20166|show=Kisah Untuk Geri|genre=Drama|contentUrl=https://www.iflix.com/title/show/20166|rating=TV-MA|contentLanguage=id"
}
}
],
Expand Down

0 comments on commit 5c74390

Please sign in to comment.