Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pubmatic: add dctr and pmzoneid params #1320

Merged
merged 4 commits into from
Jun 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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