Skip to content

Commit 5ff5b60

Browse files
committed
Merge branch 'refs/heads/master' into multiple-bidder-codes
2 parents d579a85 + fc6613f commit 5ff5b60

36 files changed

+1800
-6
lines changed

extra/modules/greenbids-real-time-data/pom.xml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,18 +22,22 @@
2222
<dependency>
2323
<groupId>com.microsoft.onnxruntime</groupId>
2424
<artifactId>onnxruntime</artifactId>
25-
<version>1.16.1</version> <!-- Use the latest available version -->
25+
<version>1.20.0</version>
2626
</dependency>
2727

2828
<dependency>
2929
<groupId>com.google.cloud</groupId>
3030
<artifactId>google-cloud-storage</artifactId>
31-
<version>2.41.0</version>
31+
<version>2.48.0</version>
3232
<exclusions>
3333
<exclusion>
3434
<groupId>commons-logging</groupId>
3535
<artifactId>commons-logging</artifactId>
3636
</exclusion>
37+
<exclusion>
38+
<groupId>com.google.guava</groupId>
39+
<artifactId>failureaccess</artifactId>
40+
</exclusion>
3741
</exclusions>
3842
</dependency>
3943
</dependencies>
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
package org.prebid.server.bidder.adverxo;
2+
3+
import com.fasterxml.jackson.core.type.TypeReference;
4+
import com.iab.openrtb.request.BidRequest;
5+
import com.iab.openrtb.request.Imp;
6+
import com.iab.openrtb.response.Bid;
7+
import com.iab.openrtb.response.BidResponse;
8+
import com.iab.openrtb.response.SeatBid;
9+
import org.apache.commons.collections4.CollectionUtils;
10+
import org.apache.commons.lang3.StringUtils;
11+
import org.prebid.server.bidder.Bidder;
12+
import org.prebid.server.bidder.model.BidderBid;
13+
import org.prebid.server.bidder.model.BidderCall;
14+
import org.prebid.server.bidder.model.BidderError;
15+
import org.prebid.server.bidder.model.HttpRequest;
16+
import org.prebid.server.bidder.model.Price;
17+
import org.prebid.server.bidder.model.Result;
18+
import org.prebid.server.currency.CurrencyConversionService;
19+
import org.prebid.server.exception.PreBidException;
20+
import org.prebid.server.json.DecodeException;
21+
import org.prebid.server.json.JacksonMapper;
22+
import org.prebid.server.proto.openrtb.ext.ExtPrebid;
23+
import org.prebid.server.proto.openrtb.ext.request.adverxo.ExtImpAdverxo;
24+
import org.prebid.server.proto.openrtb.ext.response.BidType;
25+
import org.prebid.server.util.BidderUtil;
26+
import org.prebid.server.util.HttpUtil;
27+
28+
import java.math.BigDecimal;
29+
import java.util.ArrayList;
30+
import java.util.Collection;
31+
import java.util.Collections;
32+
import java.util.List;
33+
import java.util.Objects;
34+
import java.util.stream.Collectors;
35+
36+
public class AdverxoBidder implements Bidder<BidRequest> {
37+
38+
private static final TypeReference<ExtPrebid<?, ExtImpAdverxo>> ADVERXO_EXT_TYPE_REFERENCE =
39+
new TypeReference<>() {
40+
};
41+
private static final String DEFAULT_BID_CURRENCY = "USD";
42+
private static final String ADUNIT_MACROS_ENDPOINT = "{{adUnitId}}";
43+
private static final String AUTH_MACROS_ENDPOINT = "{{auth}}";
44+
private static final String PRICE_MACRO = "${AUCTION_PRICE}";
45+
46+
private final String endpointUrl;
47+
private final JacksonMapper mapper;
48+
private final CurrencyConversionService currencyConversionService;
49+
50+
public AdverxoBidder(String endpointUrl,
51+
JacksonMapper mapper,
52+
CurrencyConversionService currencyConversionService) {
53+
54+
this.endpointUrl = HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl));
55+
this.mapper = mapper;
56+
this.currencyConversionService = currencyConversionService;
57+
}
58+
59+
@Override
60+
public Result<List<HttpRequest<BidRequest>>> makeHttpRequests(BidRequest request) {
61+
final List<BidderError> errors = new ArrayList<>();
62+
final List<HttpRequest<BidRequest>> requests = new ArrayList<>();
63+
64+
for (Imp imp : request.getImp()) {
65+
try {
66+
final ExtImpAdverxo extImp = parseImpExt(imp);
67+
final String endpoint = resolveEndpoint(extImp);
68+
final Imp modifiedImp = modifyImp(request, imp);
69+
final BidRequest outgoingRequest = createRequest(request, modifiedImp);
70+
71+
requests.add(BidderUtil.defaultRequest(outgoingRequest, endpoint, mapper));
72+
} catch (PreBidException e) {
73+
errors.add(BidderError.badInput(e.getMessage()));
74+
}
75+
}
76+
77+
return Result.of(requests, errors);
78+
}
79+
80+
private ExtImpAdverxo parseImpExt(Imp imp) {
81+
try {
82+
return mapper.mapper().convertValue(imp.getExt(), ADVERXO_EXT_TYPE_REFERENCE).getBidder();
83+
} catch (IllegalArgumentException e) {
84+
throw new PreBidException("Error parsing ext.imp.bidder: " + e.getMessage());
85+
}
86+
}
87+
88+
private String resolveEndpoint(ExtImpAdverxo extImp) {
89+
return endpointUrl
90+
.replace(ADUNIT_MACROS_ENDPOINT, Objects.toString(extImp.getAdUnitId(), "0"))
91+
.replace(AUTH_MACROS_ENDPOINT, HttpUtil.encodeUrl(StringUtils.defaultString(extImp.getAuth())));
92+
}
93+
94+
private Imp modifyImp(BidRequest bidRequest, Imp imp) {
95+
final Price resolvedBidFloor = resolveBidFloor(imp, bidRequest);
96+
97+
return imp.toBuilder()
98+
.bidfloor(resolvedBidFloor.getValue())
99+
.bidfloorcur(resolvedBidFloor.getCurrency())
100+
.build();
101+
}
102+
103+
private Price resolveBidFloor(Imp imp, BidRequest bidRequest) {
104+
final Price initialBidFloorPrice = Price.of(imp.getBidfloorcur(), imp.getBidfloor());
105+
return BidderUtil.shouldConvertBidFloor(initialBidFloorPrice, DEFAULT_BID_CURRENCY)
106+
? convertBidFloor(initialBidFloorPrice, bidRequest)
107+
: initialBidFloorPrice;
108+
}
109+
110+
private Price convertBidFloor(Price bidFloorPrice, BidRequest bidRequest) {
111+
final BigDecimal convertedPrice = currencyConversionService.convertCurrency(
112+
bidFloorPrice.getValue(),
113+
bidRequest,
114+
bidFloorPrice.getCurrency(),
115+
DEFAULT_BID_CURRENCY);
116+
117+
return Price.of(DEFAULT_BID_CURRENCY, convertedPrice);
118+
}
119+
120+
private static BidRequest createRequest(BidRequest originalRequest, Imp modifiedImp) {
121+
return originalRequest.toBuilder()
122+
.imp(Collections.singletonList(modifiedImp))
123+
.build();
124+
}
125+
126+
@Override
127+
public Result<List<BidderBid>> makeBids(BidderCall<BidRequest> httpCall, BidRequest bidRequest) {
128+
try {
129+
final BidResponse bidResponse = mapper.decodeValue(httpCall.getResponse().getBody(), BidResponse.class);
130+
return Result.withValues(extractBids(bidResponse));
131+
} catch (DecodeException | PreBidException e) {
132+
return Result.withError(BidderError.badServerResponse(e.getMessage()));
133+
}
134+
}
135+
136+
private List<BidderBid> extractBids(BidResponse bidResponse) {
137+
if (bidResponse == null || CollectionUtils.isEmpty(bidResponse.getSeatbid())) {
138+
return Collections.emptyList();
139+
}
140+
141+
return bidResponse.getSeatbid().stream()
142+
.filter(Objects::nonNull)
143+
.map(SeatBid::getBid)
144+
.filter(Objects::nonNull)
145+
.flatMap(Collection::stream)
146+
.filter(Objects::nonNull)
147+
.map(bid -> makeBid(bid, bidResponse.getCur()))
148+
.collect(Collectors.toList());
149+
}
150+
151+
private BidderBid makeBid(Bid bid, String currency) {
152+
final BidType bidType = getBidType(bid.getMtype());
153+
final String resolvedAdm = bidType == BidType.xNative ? resolveAdm(bid.getAdm(), bid.getPrice()) : bid.getAdm();
154+
final Bid processedBid = processBidMacros(bid, resolvedAdm);
155+
156+
return BidderBid.of(processedBid, bidType, currency);
157+
}
158+
159+
private static BidType getBidType(Integer mType) {
160+
return switch (mType) {
161+
case 1 -> BidType.banner;
162+
case 2 -> BidType.video;
163+
case 4 -> BidType.xNative;
164+
case null, default -> throw new PreBidException("Unsupported mType " + mType);
165+
};
166+
}
167+
168+
private static Bid processBidMacros(Bid bid, String adm) {
169+
final String price = bid.getPrice() != null ? bid.getPrice().toPlainString() : "0";
170+
171+
return bid.toBuilder()
172+
.adm(replaceMacro(adm, price))
173+
.build();
174+
}
175+
176+
private static String replaceMacro(String input, String value) {
177+
return input != null ? input.replace(PRICE_MACRO, value) : null;
178+
}
179+
180+
private static String resolveAdm(String bidAdm, BigDecimal price) {
181+
return StringUtils.isNotBlank(bidAdm) ? bidAdm.replace("${AUCTION_PRICE}", String.valueOf(price)) : bidAdm;
182+
}
183+
}

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,12 @@ private static Map<String, BidType> impIdToBidType(BidRequest bidRequest) {
314314
}
315315

316316
private static BidType getBidType(Bid bid, Map<String, BidType> impIdToBidType) {
317-
return impIdToBidType.getOrDefault(bid.getImpid(), BidType.banner);
317+
return switch (bid.getMtype()) {
318+
case 1 -> BidType.banner;
319+
case 2 -> BidType.video;
320+
case 4 -> BidType.xNative;
321+
case null, default -> impIdToBidType.getOrDefault(bid.getImpid(), BidType.banner);
322+
};
318323
}
319324

320325
private static List<ExtIgi> extractIgi(OpenxBidResponse bidResponse) {
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package org.prebid.server.proto.openrtb.ext.request.adverxo;
2+
3+
import com.fasterxml.jackson.annotation.JsonProperty;
4+
import lombok.Value;
5+
6+
@Value(staticConstructor = "of")
7+
public class ExtImpAdverxo {
8+
9+
@JsonProperty("adUnitId")
10+
Integer adUnitId;
11+
12+
String auth;
13+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package org.prebid.server.spring.config.bidder;
2+
3+
import org.prebid.server.bidder.BidderDeps;
4+
import org.prebid.server.bidder.adverxo.AdverxoBidder;
5+
import org.prebid.server.currency.CurrencyConversionService;
6+
import org.prebid.server.json.JacksonMapper;
7+
import org.prebid.server.spring.config.bidder.model.BidderConfigurationProperties;
8+
import org.prebid.server.spring.config.bidder.util.BidderDepsAssembler;
9+
import org.prebid.server.spring.config.bidder.util.UsersyncerCreator;
10+
import org.prebid.server.spring.env.YamlPropertySourceFactory;
11+
import org.springframework.beans.factory.annotation.Value;
12+
import org.springframework.boot.context.properties.ConfigurationProperties;
13+
import org.springframework.context.annotation.Bean;
14+
import org.springframework.context.annotation.Configuration;
15+
import org.springframework.context.annotation.PropertySource;
16+
17+
import jakarta.validation.constraints.NotBlank;
18+
19+
@Configuration
20+
@PropertySource(value = "classpath:/bidder-config/adverxo.yaml", factory = YamlPropertySourceFactory.class)
21+
public class AdverxoBidderConfiguration {
22+
23+
private static final String BIDDER_NAME = "adverxo";
24+
25+
@Bean("adverxoConfigurationProperties")
26+
@ConfigurationProperties("adapters.adverxo")
27+
BidderConfigurationProperties configurationProperties() {
28+
return new BidderConfigurationProperties();
29+
}
30+
31+
@Bean
32+
BidderDeps adverxoBidderDeps(BidderConfigurationProperties adverxoConfigurationProperties,
33+
@NotBlank @Value("${external-url}") String externalUrl,
34+
JacksonMapper mapper,
35+
CurrencyConversionService currencyConversionService) {
36+
37+
return BidderDepsAssembler.forBidder(BIDDER_NAME)
38+
.withConfig(adverxoConfigurationProperties)
39+
.usersyncerCreator(UsersyncerCreator.create(externalUrl))
40+
.bidderCreator(config -> new AdverxoBidder(config.getEndpoint(), mapper, currencyConversionService))
41+
.assemble();
42+
}
43+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
adapters:
2+
adverxo:
3+
endpoint: https://pbsadverxo.com/auction?adUnitId={{adUnitId}}&auth={{auth}}
4+
endpoint-compression: gzip
5+
aliases:
6+
adport:
7+
enabled: false
8+
endpoint: https://adport.pbsadverxo.com/auction?id={{adUnitId}}&auth={{auth}}
9+
usersync:
10+
enabled: false
11+
cookie-family-name: adport
12+
iframe:
13+
url: https://adport.pbsadverxo.com/usync?type=iframe&gdpr={{gdpr}}&consent={{gdpr_consent}}&us_privacy={{us_privacy}}&redirect={{redirect_url}}
14+
uid-macro: '$UID'
15+
support-cors: false
16+
redirect:
17+
url: https://adport.pbsadverxo.com/usync?type=image&gdpr={{gdpr}}&consent={{gdpr_consent}}&us_privacy={{us_privacy}}&redirect={{redirect_url}}
18+
uid-macro: '$UID'
19+
support-cors: false
20+
bidsmind:
21+
enabled: false
22+
endpoint: https://bidsmind.pbsadverxo.com/auction?id={{adUnitId}}&auth={{auth}}
23+
usersync:
24+
enabled: false
25+
cookie-family-name: bidsmind
26+
iframe:
27+
url: https://bidsmind.pbsadverxo.com/usync?type=iframe&gdpr={{gdpr}}&consent={{gdpr_consent}}&us_privacy={{us_privacy}}&redirect={{redirect_url}}
28+
uid-macro: '$UID'
29+
support-cors: false
30+
redirect:
31+
url: https://bidsmind.pbsadverxo.com/usync?type=image&gdpr={{gdpr}}&consent={{gdpr_consent}}&us_privacy={{us_privacy}}&redirect={{redirect_url}}
32+
uid-macro: '$UID'
33+
support-cors: false
34+
mobupps:
35+
enabled: false
36+
endpoint: https://mobupps.pbsadverxo.com/auction?id={{adUnitId}}&auth={{auth}}
37+
usersync:
38+
enabled: false
39+
cookie-family-name: mobupps
40+
iframe:
41+
url: https://mobupps.pbsadverxo.com/usync?type=iframe&gdpr={{gdpr}}&consent={{gdpr_consent}}&us_privacy={{us_privacy}}&redirect={{redirect_url}}
42+
uid-macro: '$UID'
43+
support-cors: false
44+
redirect:
45+
url: https://mobupps.pbsadverxo.com/usync?type=image&gdpr={{gdpr}}&consent={{gdpr_consent}}&us_privacy={{us_privacy}}&redirect={{redirect_url}}
46+
uid-macro: '$UID'
47+
support-cors: false
48+
meta-info:
49+
maintainer-email: developer@adverxo.com
50+
app-media-types:
51+
- banner
52+
- native
53+
- video
54+
site-media-types:
55+
- banner
56+
- native
57+
- video
58+
supported-vendors:
59+
vendor-id: 0
60+
usersync:
61+
cookie-family-name: adverxo
62+
iframe:
63+
url: https://pbsadverxo.com/usync?type=iframe&gdpr={{gdpr}}&consent={{gdpr_consent}}&us_privacy={{us_privacy}}&redirect={{redirect_url}}
64+
support-cors: false
65+
uid-macro: '$UID'
66+
redirect:
67+
url: https://pbsadverxo.com/usync?type=image&gdpr={{gdpr}}&consent={{gdpr_consent}}&us_privacy={{us_privacy}}&redirect={{redirect_url}}
68+
support-cors: false
69+
uid-macro: '$UID'
70+

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ adapters:
4141
streamlyn:
4242
enabled: false
4343
endpoint: http://rtba.bidsxchange.com/openrtb/{{PublisherID}}?host={{Host}}
44+
streamvision :
45+
enabled: false
46+
endpoint: http://ads-pbs.adops.streamvisionmedia.com/openrtb/{{PublisherID}}?host={{Host}}
4447
meta-info:
4548
maintainer-email: engineering@project-limelight.com
4649
app-media-types:
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-04/schema#",
3+
"title": "Adverxo Adapter Params",
4+
"description": "A schema which validates params accepted by the Adverxo adapter",
5+
"type": "object",
6+
"properties": {
7+
"adUnitId": {
8+
"type": "integer",
9+
"minimum": 1,
10+
"description": "Unique identifier for the ad unit in Adverxo platform."
11+
},
12+
"auth": {
13+
"type": "string",
14+
"minLength": 6,
15+
"description": "Authentication token provided by Adverxo platform for the AdUnit."
16+
}
17+
},
18+
"required": ["adUnitId", "auth"]
19+
}

0 commit comments

Comments
 (0)