Skip to content

Commit 9e8ea0f

Browse files
AntoxaAntoxicRitesh Ghodrao
authored andcommitted
Visx Adapter: Relay bid currency from bid respons (prebid#4077)
1 parent cc2fe19 commit 9e8ea0f

4 files changed

Lines changed: 100 additions & 29 deletions

File tree

src/main/java/org/prebid/server/bidder/visx/VisxBidder.java

Lines changed: 43 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
package org.prebid.server.bidder.visx;
22

3-
import com.fasterxml.jackson.databind.JsonNode;
3+
import com.fasterxml.jackson.core.type.TypeReference;
44
import com.fasterxml.jackson.databind.node.ObjectNode;
55
import com.iab.openrtb.request.BidRequest;
6+
import com.iab.openrtb.request.Device;
67
import com.iab.openrtb.request.Imp;
78
import com.iab.openrtb.response.Bid;
9+
import io.vertx.core.MultiMap;
810
import org.apache.commons.collections4.CollectionUtils;
11+
import org.apache.commons.lang3.StringUtils;
912
import org.prebid.server.bidder.Bidder;
1013
import org.prebid.server.bidder.model.BidderBid;
1114
import org.prebid.server.bidder.model.BidderCall;
@@ -18,21 +21,28 @@
1821
import org.prebid.server.exception.PreBidException;
1922
import org.prebid.server.json.DecodeException;
2023
import org.prebid.server.json.JacksonMapper;
24+
import org.prebid.server.proto.openrtb.ext.ExtPrebid;
2125
import org.prebid.server.proto.openrtb.ext.response.BidType;
26+
import org.prebid.server.proto.openrtb.ext.response.ExtBidPrebid;
27+
import org.prebid.server.proto.openrtb.ext.response.ExtBidPrebidMeta;
2228
import org.prebid.server.util.BidderUtil;
2329
import org.prebid.server.util.HttpUtil;
2430

2531
import java.util.Collection;
2632
import java.util.Collections;
2733
import java.util.List;
2834
import java.util.Objects;
35+
import java.util.Optional;
2936
import java.util.Set;
3037

3138
public class VisxBidder implements Bidder<BidRequest> {
3239

3340
private static final String DEFAULT_REQUEST_CURRENCY = "USD";
3441
private static final Set<String> SUPPORTED_BID_TYPES_TEXTUAL = Set.of("banner", "video");
3542

43+
private static final TypeReference<ExtPrebid<ExtBidPrebid, ?>> BID_EXT_TYPE_REFERENCE = new TypeReference<>() {
44+
};
45+
3646
private final String endpointUrl;
3747
private final JacksonMapper mapper;
3848

@@ -43,20 +53,28 @@ public VisxBidder(String endpointUrl, JacksonMapper mapper) {
4353

4454
@Override
4555
public Result<List<HttpRequest<BidRequest>>> makeHttpRequests(BidRequest request) {
46-
return Result.withValue(makeRequest(request));
47-
}
48-
49-
private HttpRequest<BidRequest> makeRequest(BidRequest bidRequest) {
50-
final BidRequest outgoingRequest = modifyRequest(bidRequest);
51-
return BidderUtil.defaultRequest(outgoingRequest, endpointUrl, mapper);
56+
final BidRequest outgoingRequest = modifyRequest(request);
57+
return Result.withValue(
58+
BidderUtil.defaultRequest(outgoingRequest, makeHeaders(request.getDevice()), endpointUrl, mapper));
5259
}
5360

54-
private BidRequest modifyRequest(BidRequest bidRequest) {
61+
private static BidRequest modifyRequest(BidRequest bidRequest) {
5562
return CollectionUtils.isEmpty(bidRequest.getCur())
5663
? bidRequest.toBuilder().cur(Collections.singletonList(DEFAULT_REQUEST_CURRENCY)).build()
5764
: bidRequest;
5865
}
5966

67+
private static MultiMap makeHeaders(Device device) {
68+
final MultiMap headers = HttpUtil.headers();
69+
70+
if (device != null) {
71+
HttpUtil.addHeaderIfValueIsNotEmpty(headers, HttpUtil.X_FORWARDED_FOR_HEADER, device.getIp());
72+
HttpUtil.addHeaderIfValueIsNotEmpty(headers, HttpUtil.X_FORWARDED_FOR_HEADER, device.getIpv6());
73+
}
74+
75+
return headers;
76+
}
77+
6078
@Override
6179
public Result<List<BidderBid>> makeBids(BidderCall<BidRequest> httpCall, BidRequest bidRequest) {
6280
try {
@@ -80,14 +98,14 @@ private List<BidderBid> bidsFromResponse(BidRequest bidRequest, VisxResponse vis
8098
.map(VisxSeatBid::getBid)
8199
.filter(Objects::nonNull)
82100
.flatMap(Collection::stream)
83-
.map(visxBid -> toBidderBid(bidRequest, visxBid))
101+
.map(visxBid -> toBidderBid(bidRequest, visxBid, visxResponse.getCur()))
84102
.toList();
85103
}
86104

87-
private BidderBid toBidderBid(BidRequest bidRequest, VisxBid visxBid) {
105+
private BidderBid toBidderBid(BidRequest bidRequest, VisxBid visxBid, String currency) {
88106
final Bid bid = toBid(visxBid, bidRequest.getId());
89107
final BidType bidType = getBidType(bid.getExt(), bid.getImpid(), bidRequest.getImp());
90-
return BidderBid.of(bid, bidType, null);
108+
return BidderBid.of(bid, bidType, StringUtils.defaultIfBlank(currency, null));
91109
}
92110

93111
private static Bid toBid(VisxBid visxBid, String id) {
@@ -105,20 +123,24 @@ private static Bid toBid(VisxBid visxBid, String id) {
105123
.build();
106124
}
107125

108-
private static BidType getBidType(ObjectNode bidExt, String impId, List<Imp> imps) {
126+
private BidType getBidType(ObjectNode bidExt, String impId, List<Imp> imps) {
109127
final BidType extBidType = getBidTypeFromExt(bidExt);
110128
return extBidType != null ? extBidType : getBidTypeFromImp(impId, imps);
111129
}
112130

113-
private static BidType getBidTypeFromExt(ObjectNode bidExt) {
114-
final JsonNode mediaTypeNode = bidExt != null ? bidExt.at("/prebid/meta/mediaType") : null;
115-
final String bidTypeTextual = mediaTypeNode != null && mediaTypeNode.isTextual()
116-
? mediaTypeNode.asText()
117-
: null;
118-
119-
return bidTypeTextual != null && SUPPORTED_BID_TYPES_TEXTUAL.contains(bidTypeTextual)
120-
? BidType.valueOf(bidTypeTextual)
121-
: null;
131+
private BidType getBidTypeFromExt(ObjectNode bidExt) {
132+
try {
133+
return Optional.ofNullable(bidExt)
134+
.map(ext -> mapper.mapper().convertValue(bidExt, BID_EXT_TYPE_REFERENCE))
135+
.map(ExtPrebid::getPrebid)
136+
.map(ExtBidPrebid::getMeta)
137+
.map(ExtBidPrebidMeta::getMediaType)
138+
.filter(SUPPORTED_BID_TYPES_TEXTUAL::contains)
139+
.map(BidType::valueOf)
140+
.orElse(null);
141+
} catch (IllegalArgumentException e) {
142+
return null;
143+
}
122144
}
123145

124146
private static BidType getBidTypeFromImp(String impId, List<Imp> imps) {

src/main/java/org/prebid/server/bidder/visx/model/VisxResponse.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,6 @@
88
public class VisxResponse {
99

1010
List<VisxSeatBid> seatbid;
11+
12+
String cur;
1113
}

src/main/resources/bidder-config/visx.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
adapters:
22
visx:
3-
endpoint: https://t.visx.net/s2s_bid?wrapperType=s2s_prebid_java
3+
endpoint: https://t.visx.net/s2s_bid?wrapperType=s2s_prebid_standard:0.1.2
44
meta-info:
55
maintainer-email: supply.partners@yoc.com
66
app-media-types:

src/test/java/org/prebid/server/bidder/visx/VisxBidderTest.java

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import com.fasterxml.jackson.databind.node.TextNode;
66
import com.iab.openrtb.request.Banner;
77
import com.iab.openrtb.request.BidRequest;
8+
import com.iab.openrtb.request.Device;
89
import com.iab.openrtb.request.Imp;
910
import com.iab.openrtb.request.Video;
1011
import com.iab.openrtb.response.Bid;
@@ -22,16 +23,19 @@
2223
import org.prebid.server.bidder.visx.model.VisxSeatBid;
2324
import org.prebid.server.proto.openrtb.ext.ExtPrebid;
2425
import org.prebid.server.proto.openrtb.ext.request.visx.ExtImpVisx;
26+
import org.prebid.server.util.HttpUtil;
2527

2628
import java.math.BigDecimal;
2729
import java.util.Arrays;
2830
import java.util.List;
31+
import java.util.Map;
2932
import java.util.function.UnaryOperator;
3033

3134
import static java.util.Collections.singletonList;
3235
import static java.util.function.UnaryOperator.identity;
3336
import static org.assertj.core.api.Assertions.assertThat;
3437
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
38+
import static org.assertj.core.api.Assertions.tuple;
3539
import static org.prebid.server.proto.openrtb.ext.response.BidType.banner;
3640
import static org.prebid.server.proto.openrtb.ext.response.BidType.video;
3741

@@ -68,6 +72,48 @@ public void makeHttpRequestsShouldNotModifyIncomingRequest() {
6872
.containsExactly(bidRequest);
6973
}
7074

75+
@Test
76+
public void makeHttpRequestsShouldAddIp() {
77+
// given
78+
final BidRequest bidRequest = BidRequest.builder()
79+
.imp(singletonList(Imp.builder()
80+
.ext(mapper.valueToTree(ExtPrebid.of(null,
81+
ExtImpVisx.of(123, Arrays.asList(10, 20)))))
82+
.build()))
83+
.device(Device.builder().ip("someIp").ipv6("ipv6").build())
84+
.build();
85+
86+
// when
87+
final Result<List<HttpRequest<BidRequest>>> result = target.makeHttpRequests(bidRequest);
88+
89+
// then
90+
assertThat(result.getValue())
91+
.flatExtracting(res -> res.getHeaders().entries())
92+
.extracting(Map.Entry::getKey, Map.Entry::getValue)
93+
.contains(tuple(HttpUtil.X_FORWARDED_FOR_HEADER.toString(), "someIp"));
94+
}
95+
96+
@Test
97+
public void makeHttpRequestsShouldAddIpv6IfIpIsNotPresent() {
98+
// given
99+
final BidRequest bidRequest = BidRequest.builder()
100+
.imp(singletonList(Imp.builder()
101+
.ext(mapper.valueToTree(ExtPrebid.of(null,
102+
ExtImpVisx.of(123, Arrays.asList(10, 20)))))
103+
.build()))
104+
.device(Device.builder().ipv6("ipv6").build())
105+
.build();
106+
107+
// when
108+
final Result<List<HttpRequest<BidRequest>>> result = target.makeHttpRequests(bidRequest);
109+
110+
// then
111+
assertThat(result.getValue())
112+
.flatExtracting(res -> res.getHeaders().entries())
113+
.extracting(Map.Entry::getKey, Map.Entry::getValue)
114+
.contains(tuple(HttpUtil.X_FORWARDED_FOR_HEADER.toString(), "ipv6"));
115+
}
116+
71117
@Test
72118
public void makeBidsShouldReturnErrorIfResponseBodyCouldNotBeParsed() {
73119
// given
@@ -122,7 +168,7 @@ public void makeBidsShouldReturnBidWithTypeBannerIfBannerIsPresent() throws Json
122168
// then
123169
assertThat(result.getErrors()).isEmpty();
124170
assertThat(result.getValue()).containsExactly(
125-
BidderBid.of(Bid.builder().id("id").impid("123").build(), banner, null));
171+
BidderBid.of(Bid.builder().id("id").impid("123").build(), banner, "USD"));
126172
}
127173

128174
@Test
@@ -138,7 +184,7 @@ public void makeBidsShouldReturnBidWithTypeBannerIfVideoIsPresentAndBannerIsAbse
138184
// then
139185
assertThat(result.getErrors()).isEmpty();
140186
assertThat(result.getValue()).containsExactly(
141-
BidderBid.of(Bid.builder().id("id").impid("123").build(), video, null));
187+
BidderBid.of(Bid.builder().id("id").impid("123").build(), video, "USD"));
142188
}
143189

144190
@Test
@@ -194,7 +240,7 @@ public void makeBidsShouldFavourBidExtMediaTypeToImpMediaTypeWhenPresent() throw
194240
// then
195241
assertThat(result.getErrors()).isEmpty();
196242
assertThat(result.getValue())
197-
.containsExactly(BidderBid.of(givenBid(identity()), banner, null));
243+
.containsExactly(BidderBid.of(givenBid(identity()), banner, "USD"));
198244
}
199245

200246
@Test
@@ -213,7 +259,7 @@ public void makeBidsShouldReturnImpMediaTypeWhenBidExtMediaTypeIsAbsent() throws
213259
// then
214260
assertThat(result.getErrors()).isEmpty();
215261
assertThat(result.getValue()).containsExactly(
216-
BidderBid.of(givenBid(bidBuilder -> bidBuilder.ext(null)), video, null));
262+
BidderBid.of(givenBid(bidBuilder -> bidBuilder.ext(null)), video, "USD"));
217263
}
218264

219265
@Test
@@ -235,7 +281,7 @@ public void makeBidsShouldReturnImpMediaTypeWhenBidExtMediaTypeIsInvalid() throw
235281
// then
236282
assertThat(result.getErrors()).isEmpty();
237283
assertThat(result.getValue()).containsExactly(
238-
BidderBid.of(givenBid(bidBuilder -> bidBuilder.ext(givenBidExt("123"))), video, null));
284+
BidderBid.of(givenBid(bidBuilder -> bidBuilder.ext(givenBidExt("123"))), video, "USD"));
239285
}
240286

241287
@Test
@@ -289,7 +335,8 @@ public void makeBidsShouldReturnCorrectBidderBid() throws JsonProcessingExceptio
289335
.h(100)
290336
.adomain(singletonList("adomain"))
291337
.build(),
292-
video, null);
338+
video,
339+
"USD");
293340

294341
assertThat(result.getErrors()).isEmpty();
295342
assertThat(result.getValue()).containsExactly(expected);
@@ -314,7 +361,7 @@ private static Imp givenImp(UnaryOperator<Imp.ImpBuilder> impCustomizer) {
314361

315362
private static VisxResponse givenVisxResponse(UnaryOperator<VisxBid.VisxBidBuilder> bidCustomizer, String seat) {
316363
return VisxResponse.of(singletonList(VisxSeatBid.of(
317-
singletonList(bidCustomizer.apply(VisxBid.builder()).build()), seat)));
364+
singletonList(bidCustomizer.apply(VisxBid.builder()).build()), seat)), "USD");
318365
}
319366

320367
private static Bid givenBid(UnaryOperator<Bid.BidBuilder> bidCustomizer) {

0 commit comments

Comments
 (0)