Skip to content

Commit 8b335a7

Browse files
committed
return buyer exts in response to DSP
1 parent d1b64ac commit 8b335a7

3 files changed

Lines changed: 189 additions & 2 deletions

File tree

src/main/java/org/prebid/server/bidder/openx/OpenxBidder.java

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import org.prebid.server.bidder.model.HttpRequest;
1818
import org.prebid.server.bidder.model.Result;
1919
import org.prebid.server.bidder.openx.model.OpenxImpType;
20+
import org.prebid.server.bidder.openx.proto.OpenxBidExt;
2021
import org.prebid.server.bidder.openx.proto.OpenxBidResponse;
2122
import org.prebid.server.bidder.openx.proto.OpenxBidResponseExt;
2223
import org.prebid.server.bidder.openx.proto.OpenxRequestExt;
@@ -29,6 +30,8 @@
2930
import org.prebid.server.proto.openrtb.ext.request.ExtRequest;
3031
import org.prebid.server.proto.openrtb.ext.request.openx.ExtImpOpenx;
3132
import org.prebid.server.proto.openrtb.ext.response.BidType;
33+
import org.prebid.server.proto.openrtb.ext.response.ExtBidPrebid;
34+
import org.prebid.server.proto.openrtb.ext.response.ExtBidPrebidMeta;
3235
import org.prebid.server.proto.openrtb.ext.response.ExtBidPrebidVideo;
3336
import org.prebid.server.proto.openrtb.ext.response.ExtIgi;
3437
import org.prebid.server.proto.openrtb.ext.response.ExtIgiIgs;
@@ -59,6 +62,9 @@ public class OpenxBidder implements Bidder<BidRequest> {
5962
private static final TypeReference<ExtPrebid<ExtImpPrebid, ExtImpOpenx>> OPENX_EXT_TYPE_REFERENCE =
6063
new TypeReference<>() {
6164
};
65+
private static final TypeReference<ExtPrebid<ExtBidPrebid, ObjectNode>> EXT_PREBID_TYPE_REFERENCE =
66+
new TypeReference<>() {
67+
};
6268

6369
private final String endpointUrl;
6470
private final JacksonMapper mapper;
@@ -270,13 +276,13 @@ private ObjectNode makeImpExt(ObjectNode impExt, boolean addCustomParams) {
270276
return openxImpExt;
271277
}
272278

273-
private static List<BidderBid> extractBids(BidRequest bidRequest, OpenxBidResponse bidResponse) {
279+
private List<BidderBid> extractBids(BidRequest bidRequest, OpenxBidResponse bidResponse) {
274280
return bidResponse == null || CollectionUtils.isEmpty(bidResponse.getSeatbid())
275281
? Collections.emptyList()
276282
: bidsFromResponse(bidRequest, bidResponse);
277283
}
278284

279-
private static List<BidderBid> bidsFromResponse(BidRequest bidRequest, OpenxBidResponse bidResponse) {
285+
private List<BidderBid> bidsFromResponse(BidRequest bidRequest, OpenxBidResponse bidResponse) {
280286
final Map<String, BidType> impIdToBidType = impIdToBidType(bidRequest);
281287

282288
final String bidCurrency = StringUtils.isNotBlank(bidResponse.getCur())
@@ -288,6 +294,7 @@ private static List<BidderBid> bidsFromResponse(BidRequest bidRequest, OpenxBidR
288294
.map(SeatBid::getBid)
289295
.filter(Objects::nonNull)
290296
.flatMap(Collection::stream)
297+
.map(bid -> bid.toBuilder().ext(updateBidMeta(bid)).build())
291298
.map(bid -> toBidderBid(bid, impIdToBidType, bidCurrency))
292299
.toList();
293300
}
@@ -334,4 +341,60 @@ private static List<ExtIgi> extractIgi(OpenxBidResponse bidResponse) {
334341

335342
return igs.isEmpty() ? null : Collections.singletonList(ExtIgi.builder().igs(igs).build());
336343
}
344+
345+
private ObjectNode updateBidMeta(Bid bid) {
346+
final var ext = bid.getExt();
347+
if (ext == null) {
348+
return null;
349+
}
350+
351+
final var openxBidExt = parseOpenxBidExt(ext);
352+
final int buyerId = parseStringToInt(openxBidExt.getBuyerId());
353+
final int dspId = parseStringToInt(openxBidExt.getDspId());
354+
final int brandId = parseStringToInt(openxBidExt.getBrandId());
355+
356+
if (buyerId == 0 && dspId == 0 && brandId == 0) {
357+
return ext;
358+
}
359+
360+
final var extPrebid = getExtPrebid(ext, bid.getId());
361+
final var updatedMeta = ExtBidPrebidMeta.builder()
362+
.networkId(dspId)
363+
.advertiserId(buyerId)
364+
.brandId(brandId)
365+
.build();
366+
367+
final var modifiedExtBidPrebid = Optional.ofNullable(extPrebid.getPrebid())
368+
.map(p -> p.toBuilder().meta(updatedMeta).build())
369+
.orElse(ExtBidPrebid.builder().meta(updatedMeta).build());
370+
371+
final var updatedExt = ext.deepCopy();
372+
updatedExt.set(PREBID_EXT, mapper.mapper().valueToTree(modifiedExtBidPrebid));
373+
374+
return updatedExt;
375+
}
376+
377+
private OpenxBidExt parseOpenxBidExt(ObjectNode ext) {
378+
try {
379+
return mapper.mapper().convertValue(ext, OpenxBidExt.class);
380+
} catch (IllegalArgumentException e) {
381+
return new OpenxBidExt();
382+
}
383+
}
384+
385+
private ExtPrebid<ExtBidPrebid, ObjectNode> getExtPrebid(ObjectNode bidExt, String bidId) {
386+
try {
387+
return mapper.mapper().convertValue(bidExt, EXT_PREBID_TYPE_REFERENCE);
388+
} catch (IllegalArgumentException e) {
389+
throw new PreBidException("Invalid ext in bid with id: " + bidId, e);
390+
}
391+
}
392+
393+
private int parseStringToInt(String value) {
394+
try {
395+
return value != null ? Integer.parseInt(value) : 0;
396+
} catch (NumberFormatException e) {
397+
return 0;
398+
}
399+
}
337400
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package org.prebid.server.bidder.openx.proto;
2+
3+
import com.fasterxml.jackson.annotation.JsonProperty;
4+
import lombok.Getter;
5+
6+
@Getter
7+
public class OpenxBidExt {
8+
9+
@JsonProperty("dsp_id")
10+
String dspId;
11+
@JsonProperty("buyer_id")
12+
String buyerId;
13+
@JsonProperty("brand_id")
14+
String brandId;
15+
}

src/test/java/org/prebid/server/bidder/openx/OpenxBidderTest.java

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.fasterxml.jackson.core.JsonProcessingException;
44
import com.fasterxml.jackson.databind.JsonNode;
5+
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
56
import com.fasterxml.jackson.databind.node.ObjectNode;
67
import com.iab.openrtb.request.Audio;
78
import com.iab.openrtb.request.Banner;
@@ -990,4 +991,112 @@ private static Map<String, JsonNode> givenCustomParams(String key, Object values
990991
private static BidderCall<BidRequest> givenHttpCall(String body) {
991992
return BidderCall.succeededHttp(null, HttpResponse.of(200, null, body), null);
992993
}
994+
995+
@Test
996+
public void makeBidsShouldReturnBidMeta() throws JsonProcessingException {
997+
// given
998+
final var allBuyerExt = new ObjectNode(JsonNodeFactory.instance);
999+
final var onlyBrandExt = new ObjectNode(JsonNodeFactory.instance);
1000+
final var badExt = new ObjectNode(JsonNodeFactory.instance);
1001+
1002+
allBuyerExt.put("dsp_id", "1").put("buyer_id", "2").put("brand_id", "3");
1003+
onlyBrandExt.put("brand_id", "4");
1004+
badExt.put("dsp_id", "abc").put("brand_id", "cba");
1005+
badExt.put("something", "abc");
1006+
1007+
final var allBuyerExpectedExtJson = "{\"dsp_id\":\"1\",\"buyer_id\":\"2\",\"brand_id\":\"3\",\"prebid\":"
1008+
+ "{\"meta\":{\"advertiserId\":2,\"brandId\":3,\"networkId\":1}}}";
1009+
final var onlyBrandExpectedExtJson = "{\"brand_id\":\"4\",\"prebid\":{\"meta\":{\"advertiserId\":0,"
1010+
+ "\"brandId\":4,\"networkId\":0}}}";
1011+
final var badExpectedExtJson = "{\"dsp_id\":\"abc\",\"brand_id\":\"cba\"}";
1012+
1013+
final var allBuyerExpectedExt = (ObjectNode) mapper.readTree(allBuyerExpectedExtJson);
1014+
final var onlyBrandExpectedExt = (ObjectNode) mapper.readTree(onlyBrandExpectedExtJson);
1015+
final var badExpectedExt = (ObjectNode) mapper.readTree(badExpectedExtJson);
1016+
1017+
final BidderCall<BidRequest> httpCall = givenHttpCall(mapper.writeValueAsString(BidResponse.builder()
1018+
.seatbid(singletonList(SeatBid.builder()
1019+
.bid(List.of(
1020+
Bid.builder()
1021+
.w(200)
1022+
.h(150)
1023+
.price(BigDecimal.ONE)
1024+
.impid("impId1")
1025+
.dealid("dealid")
1026+
.adm("<div>This is an Ad</div>")
1027+
.ext(allBuyerExt)
1028+
.build(),
1029+
Bid.builder()
1030+
.w(200)
1031+
.h(150)
1032+
.price(BigDecimal.ONE)
1033+
.impid("impId1")
1034+
.dealid("dealid2")
1035+
.adm("<div>This is an Ad</div>")
1036+
.ext(onlyBrandExt)
1037+
.build(),
1038+
Bid.builder()
1039+
.w(200)
1040+
.h(150)
1041+
.price(BigDecimal.ONE)
1042+
.impid("impId1")
1043+
.dealid("dealid3")
1044+
.adm("<div>This is an Ad</div>")
1045+
.ext(badExt)
1046+
.build()
1047+
))
1048+
.build()))
1049+
.build()));
1050+
1051+
final BidRequest bidRequest = BidRequest.builder()
1052+
.id("bidRequestId")
1053+
.imp(List.of(
1054+
Imp.builder()
1055+
.id("impId1")
1056+
.banner(Banner.builder().build())
1057+
.build()
1058+
))
1059+
.build();
1060+
1061+
// when
1062+
final CompositeBidderResponse result = target.makeBidderResponse(httpCall, bidRequest);
1063+
1064+
// then
1065+
assertThat(result.getErrors()).isEmpty();
1066+
assertThat(result.getBids()).hasSize(3).containsExactlyInAnyOrder(
1067+
BidderBid.of(
1068+
Bid.builder()
1069+
.impid("impId1")
1070+
.price(BigDecimal.ONE)
1071+
.dealid("dealid")
1072+
.w(200)
1073+
.h(150)
1074+
.adm("<div>This is an Ad</div>")
1075+
.ext(allBuyerExpectedExt)
1076+
.build(),
1077+
BidType.banner, "USD"),
1078+
BidderBid.of(
1079+
Bid.builder()
1080+
.impid("impId1")
1081+
.price(BigDecimal.ONE)
1082+
.dealid("dealid2")
1083+
.w(200)
1084+
.h(150)
1085+
.adm("<div>This is an Ad</div>")
1086+
.ext(onlyBrandExpectedExt)
1087+
.build(),
1088+
BidType.banner, "USD"),
1089+
BidderBid.of(
1090+
Bid.builder()
1091+
.impid("impId1")
1092+
.price(BigDecimal.ONE)
1093+
.dealid("dealid3")
1094+
.w(200)
1095+
.h(150)
1096+
.adm("<div>This is an Ad</div>")
1097+
.ext(badExpectedExt)
1098+
.build(),
1099+
BidType.banner, "USD")
1100+
);
1101+
}
9931102
}

0 commit comments

Comments
 (0)