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

Support pubmatic video duration and primary category #849

Merged
merged 4 commits into from
Sep 18, 2020
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
29 changes: 26 additions & 3 deletions src/main/java/org/prebid/server/auction/BidResponseCreator.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.prebid.server.auction;

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.BidRequest;
Expand Down Expand Up @@ -54,6 +55,7 @@
import org.prebid.server.proto.openrtb.ext.response.CacheAsset;
import org.prebid.server.proto.openrtb.ext.response.Events;
import org.prebid.server.proto.openrtb.ext.response.ExtBidPrebid;
import org.prebid.server.proto.openrtb.ext.response.ExtBidPrebidVideo;
import org.prebid.server.proto.openrtb.ext.response.ExtBidResponse;
import org.prebid.server.proto.openrtb.ext.response.ExtBidResponsePrebid;
import org.prebid.server.proto.openrtb.ext.response.ExtBidderError;
Expand Down Expand Up @@ -85,6 +87,10 @@

public class BidResponseCreator {

private static final TypeReference<ExtPrebid<ExtBidPrebid, ObjectNode>> EXT_PREBID_TYPE_REFERENCE =
new TypeReference<ExtPrebid<ExtBidPrebid, ObjectNode>>() {
};

private static final String CACHE = "cache";
private static final String PREBID_EXT = "prebid";

Expand Down Expand Up @@ -837,9 +843,16 @@ private Bid toBid(BidderBid bidderBid,
final Events events = eventsEnabled && eventsAllowedByRequest(bidRequest)
? eventsService.createEvent(eventBidId, bidder, account.getId(), auctionTimestamp, integration)
: null;

final ExtBidPrebid prebidExt = ExtBidPrebid.of(
generatedBidId, bidType, targetingKeywords, cache, storedVideo, events, null);
final ExtBidPrebidVideo extBidPrebidVideo = getExtBidPrebidVideo(bid.getExt());
final ExtBidPrebid prebidExt = ExtBidPrebid.builder()
.bidid(generatedBidId)
.type(bidType)
.targeting(targetingKeywords)
.cache(cache)
.storedRequestAttributes(storedVideo)
.events(events)
.video(extBidPrebidVideo)
.build();

final ExtPrebid<ExtBidPrebid, ObjectNode> bidExt = ExtPrebid.of(prebidExt, bid.getExt());
bid.setExt(mapper.mapper().valueToTree(bidExt));
Expand Down Expand Up @@ -1026,4 +1039,14 @@ private String integrationFrom(AuctionContext auctionContext) {
StringUtils.stripToNull(integration),
auctionContext.getAccount().getDefaultIntegration());
}

/**
* Creates {@link ExtBidPrebidVideo} from bid extension.
*/
private ExtBidPrebidVideo getExtBidPrebidVideo(ObjectNode bidExt) {
final ExtPrebid<ExtBidPrebid, ObjectNode> extPrebid = mapper.mapper()
.convertValue(bidExt, EXT_PREBID_TYPE_REFERENCE);
final ExtBidPrebid extBidPrebid = extPrebid != null ? extPrebid.getPrebid() : null;
return extBidPrebid != null ? extBidPrebid.getVideo() : null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -187,10 +187,6 @@ private AdopplerResponseExt parseResponseExt(ObjectNode ext) {
}
}

private String head(List<String> cat) {
return cat.size() == 0 ? "" : cat.get(0);
}

@Override
public Map<String, String> extractTargeting(ObjectNode ext) {
return Collections.emptyMap();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
package org.prebid.server.bidder.pubmatic;

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;
import com.iab.openrtb.request.BidRequest;
import com.iab.openrtb.request.Imp;
import com.iab.openrtb.request.Publisher;
import com.iab.openrtb.request.Site;
import com.iab.openrtb.response.Bid;
import com.iab.openrtb.response.BidResponse;
import com.iab.openrtb.response.SeatBid;
import io.vertx.core.http.HttpMethod;
Expand All @@ -22,7 +23,9 @@
import org.prebid.server.bidder.model.HttpCall;
import org.prebid.server.bidder.model.HttpRequest;
import org.prebid.server.bidder.model.Result;
import org.prebid.server.bidder.pubmatic.proto.PubmaticBidExt;
import org.prebid.server.bidder.pubmatic.proto.PubmaticRequestExt;
import org.prebid.server.bidder.pubmatic.proto.VideoCreativeInfo;
import org.prebid.server.exception.PreBidException;
import org.prebid.server.json.DecodeException;
import org.prebid.server.json.JacksonMapper;
Expand All @@ -31,6 +34,8 @@
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;
Expand All @@ -47,7 +52,7 @@ public class PubmaticBidder implements Bidder<BidRequest> {
private static final Logger logger = LoggerFactory.getLogger(PubmaticBidder.class);

private static final String DEFAULT_BID_CURRENCY = "USD";
private static final String BID_TYPE_EXT_KEY = "BidType";
private static final String PREBID = "prebid";
private static final TypeReference<ExtPrebid<?, ExtImpPubmatic>> PUBMATIC_EXT_TYPE_REFERENCE =
new TypeReference<ExtPrebid<?, ExtImpPubmatic>>() {
};
Expand Down Expand Up @@ -255,27 +260,53 @@ public final Result<List<BidderBid>> makeBids(HttpCall<BidRequest> httpCall, Bid
}
}

private static List<BidderBid> extractBids(BidResponse bidResponse) {
private List<BidderBid> extractBids(BidResponse bidResponse) {
return bidResponse == null || bidResponse.getSeatbid() == null
? Collections.emptyList()
: bidsFromResponse(bidResponse);
}

private static List<BidderBid> bidsFromResponse(BidResponse bidResponse) {
private List<BidderBid> bidsFromResponse(BidResponse bidResponse) {
return bidResponse.getSeatbid().stream()
.filter(Objects::nonNull)
.map(SeatBid::getBid)
.filter(Objects::nonNull)
.flatMap(Collection::stream)
.map(bid -> BidderBid.of(bid, getBidType(bid.getExt()), DEFAULT_BID_CURRENCY))
.map(this::bidderBid)
.collect(Collectors.toList());
}

protected static BidType getBidType(ObjectNode bidExt) {
if (bidExt != null) {
final JsonNode bidTypeVal = bidExt.get(BID_TYPE_EXT_KEY);
private BidderBid bidderBid(Bid bid) {
final List<String> bidCat = bid.getCat();
final boolean updateBidCat = bidCat != null && bidCat.size() > 1;
final List<String> singleElementCat = updateBidCat
? Collections.singletonList(bidCat.get(0))
: bidCat;
final PubmaticBidExt pubmaticBidExt = extractBidExt(bid.getExt());
final Integer duration = getDuration(pubmaticBidExt);
final Bid updatedBid = updateBidCat || duration != null
? bid.toBuilder()
.cat(singleElementCat)
.ext(duration != null ? updateBidExtWithExtPrebid(duration, bid.getExt()) : bid.getExt())
.build()
: bid;

return BidderBid.of(updatedBid, getBidType(pubmaticBidExt), DEFAULT_BID_CURRENCY);
}

private PubmaticBidExt extractBidExt(ObjectNode bidExt) {
try {
return bidExt != null ? mapper.mapper().treeToValue(bidExt, PubmaticBidExt.class) : null;
} catch (JsonProcessingException e) {
throw new PreBidException(String.format("Error parsing pubmatic bid.ext %s", e.getMessage()));
}
}

private static BidType getBidType(PubmaticBidExt pubmaticBidExt) {
if (pubmaticBidExt != null) {
final Integer bidTypeVal = pubmaticBidExt.getBidType();
if (bidTypeVal != null) {
switch (bidTypeVal.asInt()) {
switch (bidTypeVal) {
case 1:
return BidType.video;
case 2:
Expand All @@ -288,6 +319,16 @@ protected static BidType getBidType(ObjectNode bidExt) {
return BidType.banner;
}

private static Integer getDuration(PubmaticBidExt pubmaticBidExt) {
final VideoCreativeInfo video = pubmaticBidExt != null ? pubmaticBidExt.getVideo() : null;
return video != null ? video.getDuration() : null;
}

private ObjectNode updateBidExtWithExtPrebid(Integer duration, ObjectNode extBid) {
final ExtBidPrebid extBidPrebid = ExtBidPrebid.builder().video(ExtBidPrebidVideo.of(duration, null)).build();
return extBid.set(PREBID, mapper.mapper().valueToTree(extBidPrebid));
}

@Override
public final Map<String, String> extractTargeting(ObjectNode ext) {
return Collections.emptyMap();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.prebid.server.bidder.pubmatic.proto;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Value;

@Value
@AllArgsConstructor(staticName = "of")
public class PubmaticBidExt {
@JsonProperty("BidType")
Integer bidType;

VideoCreativeInfo video;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.prebid.server.bidder.pubmatic.proto;

import lombok.AllArgsConstructor;
import lombok.Value;

@Value
@AllArgsConstructor(staticName = "of")
public class VideoCreativeInfo {

Integer duration;
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ public class ExtImpOpenx {
@JsonProperty("delDomain")
String delDomain;

@JsonProperty("platform")
String platform;

@JsonProperty("customFloor")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@

import com.fasterxml.jackson.annotation.JsonProperty;
import com.iab.openrtb.request.Video;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Value;

import java.util.Map;

/**
* Defines the contract for bidresponse.seatbid.bid[i].ext.prebid
*/
@AllArgsConstructor(staticName = "of")
@Builder
@Value
public class ExtBidPrebid {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
import org.prebid.server.proto.openrtb.ext.response.CacheAsset;
import org.prebid.server.proto.openrtb.ext.response.Events;
import org.prebid.server.proto.openrtb.ext.response.ExtBidPrebid;
import org.prebid.server.proto.openrtb.ext.response.ExtBidPrebidVideo;
import org.prebid.server.proto.openrtb.ext.response.ExtBidResponse;
import org.prebid.server.proto.openrtb.ext.response.ExtBidResponsePrebid;
import org.prebid.server.proto.openrtb.ext.response.ExtBidderError;
Expand Down Expand Up @@ -447,8 +448,7 @@ public void shouldSkipBidderResponsesWhereSeatBidContainEmptyBids() {
public void shouldOverrideBidIdWhenGenerateBidIdIsTurnedOn() {
// given
final AuctionContext auctionContext = givenAuctionContext(givenBidRequest());
final ExtPrebid<ExtBidPrebid, ?> prebid = ExtPrebid.of(ExtBidPrebid.of(null, banner, null,
null, null, null, null), null);
final ExtPrebid<ExtBidPrebid, ?> prebid = ExtPrebid.of(ExtBidPrebid.builder().type(banner).build(), null);
final Bid bid = Bid.builder()
.id("123")
.impid("imp123")
Expand Down Expand Up @@ -508,7 +508,7 @@ public void shouldSetExpectedResponseSeatBidAndBidFields() {
.price(BigDecimal.ONE)
.adm("adm")
.ext(mapper.valueToTree(ExtPrebid.of(
ExtBidPrebid.of(null, banner, null, null, null, null, null),
ExtBidPrebid.builder().type(banner).build(),
singletonMap("bidExt", 1))))
.build()))
.build());
Expand Down Expand Up @@ -787,7 +787,7 @@ public void shouldTolerateMissingExtInSeatBidAndBid() {
.impid("i1")
.price(BigDecimal.ONE)
.ext(mapper.valueToTree(
ExtPrebid.of(ExtBidPrebid.of(null, banner, null, null, null, null, null), null)))
ExtPrebid.of(ExtBidPrebid.builder().type(banner).build(), null)))
.build());

verify(cacheService, never()).cacheBidsOpenrtb(anyList(), anyList(), any(), any(), any(), any());
Expand Down Expand Up @@ -1169,6 +1169,31 @@ public void shouldAddExtPrebidEvents() {
verify(cacheService, never()).cacheBidsOpenrtb(anyList(), anyList(), any(), any(), any(), any());
}

@Test
public void shouldAddExtPrebidVideo() {
// given
final AuctionContext auctionContext = givenAuctionContext(givenBidRequest());

final Bid bid = Bid.builder().id("bidId1").price(BigDecimal.valueOf(5.67)).impid("i1").impid("i1")
.ext(mapper.createObjectNode().set("prebid", mapper.valueToTree(
ExtBidPrebid.builder().video(ExtBidPrebidVideo.of(1, "category")).build()))).build();
final List<BidderResponse> bidderResponses = singletonList(BidderResponse.of("bidder1",
givenSeatBid(BidderBid.of(bid, banner, "USD")), 100));

given(eventsService.winUrlTargeting(anyString(), anyString(), anyLong(), anyString()))
.willReturn("http://win-url");

// when
final BidResponse bidResponse =
bidResponseCreator.create(bidderResponses, auctionContext, CACHE_INFO, false).result();

// then
assertThat(bidResponse.getSeatbid()).hasSize(1)
.flatExtracting(SeatBid::getBid)
.extracting(responseBid -> toExtPrebid(responseBid.getExt()).getPrebid().getVideo())
.containsOnly(ExtBidPrebidVideo.of(1, "category"));
}

@Test
public void shouldNotAddExtPrebidEventsIfEventsAreNotEnabled() {
// given
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2333,7 +2333,7 @@ private static Bid givenBid(Function<Bid.BidBuilder, Bid.BidBuilder> bidBuilder)
return bidBuilder.apply(Bid.builder()
.id("bidId")
.price(BigDecimal.ONE)
.ext(mapper.valueToTree(ExtPrebid.of(ExtBidPrebid.of(null, null, null, null, null, null, null), null))))
.ext(mapper.valueToTree(ExtPrebid.of(ExtBidPrebid.builder().build(), null))))
.build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -558,7 +558,7 @@ public void mergeWithBidderResponsesShouldResolveBidTypeFromStoredBidExt() {
singletonList(BidderBid.of(Bid.builder().id("bid1").build(), BidType.banner, "USD")), emptyList(),
emptyList()), 100));

final ExtBidPrebid extBidPrebid = ExtBidPrebid.of(null, BidType.video, null, null, null, null, null);
final ExtBidPrebid extBidPrebid = ExtBidPrebid.builder().type(BidType.video).build();

final List<SeatBid> seatBid = singletonList(SeatBid.builder()
.seat("rubicon").bid(singletonList(Bid.builder().ext(mapper.createObjectNode()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,19 +42,19 @@ public void shouldReturnExpectedVideoResponse() {
final Bid bid0 = Bid.builder()
.impid("0_0")
.ext(mapper.valueToTree(
ExtPrebid.of(ExtBidPrebid.of(null, null, targeting, null, null, null, null),
ExtPrebid.of(ExtBidPrebid.builder().targeting(targeting).build(),
mapper.createObjectNode())))
.build();
final Bid bid1 = Bid.builder()
.impid("1_1")
.ext(mapper.valueToTree(
ExtPrebid.of(ExtBidPrebid.of(null, null, targeting, null, null, null, null),
ExtPrebid.of(ExtBidPrebid.builder().targeting(targeting).build(),
mapper.createObjectNode())))
.build();
final Bid bid2 = Bid.builder()
.impid("2_1")
.ext(mapper.valueToTree(
ExtPrebid.of(ExtBidPrebid.of(null, null, null, null, null, null, null),
ExtPrebid.of(ExtBidPrebid.builder().build(),
mapper.createObjectNode())))
.build();

Expand Down
Loading