-
Notifications
You must be signed in to change notification settings - Fork 190
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
Loyal: New Adapter (#3140) #3183
Merged
Merged
Changes from 22 commits
Commits
Show all changes
26 commits
Select commit
Hold shift + click to select a range
6afc35c
Embimedia: New Adapter (#3140)
przemkaczmarek 002f903
Small updates
Compile-Ninja 2d3c4c8
Fix checkstyle
SerhiiNahornyi b4a19f7
Add integration test
SerhiiNahornyi 0935323
Loyal: New Adapter (#3140)
przemkaczmarek c54c1d1
Merge branch 'master' into new-adapter-loyal-(#3140)
przemkaczmarek 7c62fbf
fixing checkstyle
przemkaczmarek 293252f
fixing checkstyle
przemkaczmarek 121dd13
resolve conflicts
przemkaczmarek 222b099
resolve comments
przemkaczmarek 48fe8b9
resolve comments
przemkaczmarek 9f1cdcb
resolve comments
przemkaczmarek 6a53f82
resolve comments
przemkaczmarek b145302
resolve comments
przemkaczmarek c01c80b
resolve comments
przemkaczmarek 355f5c2
resolve comments
przemkaczmarek a177a39
resolve comments
przemkaczmarek 0e8d1f2
resolve comments
przemkaczmarek c52c75d
resolve comments
przemkaczmarek ce22d7c
resolve comments
przemkaczmarek bc5aff9
resolve comments
przemkaczmarek 6298657
resolve comments
przemkaczmarek ec40194
resolve comments
przemkaczmarek 9b8a705
resolve comments
przemkaczmarek 683b1dd
resolve comments
przemkaczmarek 073459d
Minor fix
SerhiiNahornyi File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
171 changes: 171 additions & 0 deletions
171
src/main/java/org/prebid/server/bidder/loyal/LoyalBidder.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
package org.prebid.server.bidder.loyal; | ||
|
||
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; | ||
import com.iab.openrtb.request.Imp; | ||
import com.iab.openrtb.response.Bid; | ||
import com.iab.openrtb.response.BidResponse; | ||
import com.iab.openrtb.response.SeatBid; | ||
import org.apache.commons.collections4.CollectionUtils; | ||
import org.apache.commons.lang3.StringUtils; | ||
import org.prebid.server.bidder.Bidder; | ||
import org.prebid.server.bidder.loyal.proto.LoyalImpExt; | ||
import org.prebid.server.bidder.model.BidderBid; | ||
import org.prebid.server.bidder.model.BidderCall; | ||
import org.prebid.server.bidder.model.BidderError; | ||
import org.prebid.server.bidder.model.HttpRequest; | ||
import org.prebid.server.bidder.model.Result; | ||
import org.prebid.server.exception.PreBidException; | ||
import org.prebid.server.json.DecodeException; | ||
import org.prebid.server.json.JacksonMapper; | ||
import org.prebid.server.proto.openrtb.ext.ExtPrebid; | ||
import org.prebid.server.proto.openrtb.ext.request.loyal.ExtImpLoyal; | ||
import org.prebid.server.proto.openrtb.ext.response.BidType; | ||
import org.prebid.server.util.BidderUtil; | ||
import org.prebid.server.util.HttpUtil; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Collection; | ||
import java.util.Collections; | ||
import java.util.List; | ||
import java.util.Objects; | ||
import java.util.Optional; | ||
|
||
public class LoyalBidder implements Bidder<BidRequest> { | ||
|
||
private static final TypeReference<ExtPrebid<?, ExtImpLoyal>> LOYAL_EXT_TYPE_REFERENCE = | ||
new TypeReference<>() { | ||
}; | ||
|
||
private static final String PUBLISHER_PROPERTY = "publisher"; | ||
private static final String NETWORK_PROPERTY = "network"; | ||
private static final String BIDDER_PROPERTY = "bidder"; | ||
|
||
private final String endpointUrl; | ||
private final JacksonMapper mapper; | ||
|
||
public LoyalBidder(String endpointUrl, JacksonMapper mapper) { | ||
this.endpointUrl = HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl)); | ||
this.mapper = Objects.requireNonNull(mapper); | ||
} | ||
|
||
@Override | ||
public Result<List<HttpRequest<BidRequest>>> makeHttpRequests(BidRequest request) { | ||
final List<BidderError> errors = new ArrayList<>(); | ||
final List<HttpRequest<BidRequest>> httpRequests = new ArrayList<>(); | ||
|
||
for (Imp imp : request.getImp()) { | ||
try { | ||
final ExtImpLoyal extImpLoyal = parseExtImp(imp); | ||
if (isValidImp(extImpLoyal)) { | ||
final Imp modifiedImp = modifyImp(imp, extImpLoyal); | ||
httpRequests.add(makeHttpRequest(request, modifiedImp)); | ||
} else { | ||
errors.add(BidderError.badInput("Invalid imp: " + imp.getId())); | ||
} | ||
} catch (PreBidException e) { | ||
errors.add(BidderError.badInput(e.getMessage())); | ||
} | ||
} | ||
|
||
if (httpRequests.isEmpty()) { | ||
return Result.withError(BidderError.badInput("found no valid impressions")); | ||
} | ||
|
||
return Result.of(httpRequests, errors); | ||
} | ||
|
||
private ExtImpLoyal parseExtImp(Imp imp) { | ||
try { | ||
return mapper.mapper().convertValue(imp.getExt(), LOYAL_EXT_TYPE_REFERENCE).getBidder(); | ||
} catch (IllegalArgumentException e) { | ||
throw new PreBidException("Cannot deserialize ExtImpLoyal: " + e.getMessage()); | ||
} | ||
} | ||
|
||
private boolean isValidImp(ExtImpLoyal extImpLoyal) { | ||
return StringUtils.isNotEmpty(extImpLoyal.getPlacementId()) | ||
|| StringUtils.isNotEmpty(extImpLoyal.getEndpointId()); | ||
} | ||
|
||
private Imp modifyImp(Imp imp, ExtImpLoyal extImpLoyal) { | ||
final LoyalImpExt impExtLoyalWithType = resolveImpExt(extImpLoyal); | ||
final ObjectNode modifiedImpExtBidder = mapper.mapper().createObjectNode(); | ||
modifiedImpExtBidder.set(BIDDER_PROPERTY, mapper.mapper().valueToTree(impExtLoyalWithType)); | ||
|
||
return imp.toBuilder().ext(modifiedImpExtBidder).build(); | ||
} | ||
|
||
private LoyalImpExt resolveImpExt(ExtImpLoyal extImpLoyal) { | ||
final LoyalImpExt.LoyalImpExtBuilder builder = LoyalImpExt.builder(); | ||
|
||
if (StringUtils.isNotEmpty(extImpLoyal.getPlacementId())) { | ||
builder.type(PUBLISHER_PROPERTY).placementId(extImpLoyal.getPlacementId()); | ||
} else if (StringUtils.isNotEmpty(extImpLoyal.getEndpointId())) { | ||
builder.type(NETWORK_PROPERTY).endpointId(extImpLoyal.getEndpointId()); | ||
} | ||
|
||
return builder.build(); | ||
} | ||
|
||
private HttpRequest<BidRequest> makeHttpRequest(BidRequest request, Imp imp) { | ||
final BidRequest outgoingRequest = request.toBuilder().imp(List.of(imp)).build(); | ||
|
||
return BidderUtil.defaultRequest(outgoingRequest, endpointUrl, mapper); | ||
} | ||
|
||
@Override | ||
public Result<List<BidderBid>> makeBids(BidderCall<BidRequest> httpCall, BidRequest bidRequest) { | ||
try { | ||
final BidResponse bidResponse = mapper.decodeValue(httpCall.getResponse().getBody(), BidResponse.class); | ||
final List<BidderBid> bids = extractBids(httpCall.getRequest().getPayload(), bidResponse); | ||
return Result.withValues(bids); | ||
} catch (DecodeException | PreBidException e) { | ||
return Result.withError(BidderError.badServerResponse(e.getMessage())); | ||
} | ||
} | ||
|
||
private List<BidderBid> extractBids(BidRequest bidRequest, BidResponse bidResponse) { | ||
if (bidResponse == null || CollectionUtils.isEmpty(bidResponse.getSeatbid())) { | ||
return Collections.emptyList(); | ||
} | ||
|
||
return bidResponse.getSeatbid().stream() | ||
.filter(Objects::nonNull) | ||
.map(SeatBid::getBid) | ||
.filter(Objects::nonNull) | ||
.flatMap(Collection::stream) | ||
.filter(Objects::nonNull) | ||
.map(bid -> BidderBid.of(bid, getBidType(bid), bidResponse.getCur())) | ||
.toList(); | ||
} | ||
|
||
private BidType getBidType(Bid bid) { | ||
final JsonNode typeNode = Optional.ofNullable(bid.getExt()) | ||
.map(extNode -> extNode.get("prebid")) | ||
.map(extPrebidNode -> extPrebidNode.get("type")) | ||
.orElse(null); | ||
|
||
final BidType bidType; | ||
try { | ||
bidType = mapper.mapper().convertValue(typeNode, BidType.class); | ||
przemkaczmarek marked this conversation as resolved.
Show resolved
Hide resolved
przemkaczmarek marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} catch (IllegalArgumentException e) { | ||
throw new PreBidException("Failed to parse bid.ext.prebid.type for bid.id: '%s'" | ||
.formatted(bid.getId())); | ||
} | ||
|
||
if (bidType == null) { | ||
throw new PreBidException("bid.ext.prebid.type is not present for bid.id: '%s'" | ||
.formatted(bid.getId())); | ||
} | ||
|
||
return switch (bidType) { | ||
case banner, video, xNative -> bidType; | ||
default -> throw new PreBidException("Unsupported BidType: " | ||
+ bidType.getName() + " for bid.id: '" + bid.getId() + "'"); | ||
}; | ||
} | ||
|
||
} |
19 changes: 19 additions & 0 deletions
19
src/main/java/org/prebid/server/bidder/loyal/proto/LoyalImpExt.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package org.prebid.server.bidder.loyal.proto; | ||
|
||
import com.fasterxml.jackson.annotation.JsonProperty; | ||
import lombok.Builder; | ||
import lombok.Value; | ||
|
||
@Builder | ||
@Value | ||
public class LoyalImpExt { | ||
|
||
@JsonProperty("type") | ||
String type; | ||
|
||
@JsonProperty("placementId") | ||
String placementId; | ||
|
||
@JsonProperty("endpointId") | ||
String endpointId; | ||
} |
14 changes: 14 additions & 0 deletions
14
src/main/java/org/prebid/server/proto/openrtb/ext/request/loyal/ExtImpLoyal.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package org.prebid.server.proto.openrtb.ext.request.loyal; | ||
|
||
import com.fasterxml.jackson.annotation.JsonProperty; | ||
import lombok.Value; | ||
|
||
@Value(staticConstructor = "of") | ||
public class ExtImpLoyal { | ||
|
||
@JsonProperty("placementId") | ||
String placementId; | ||
|
||
@JsonProperty("endpointId") | ||
String endpointId; | ||
} |
41 changes: 41 additions & 0 deletions
41
src/main/java/org/prebid/server/spring/config/bidder/LoyalConfiguration.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package org.prebid.server.spring.config.bidder; | ||
|
||
import org.prebid.server.bidder.BidderDeps; | ||
import org.prebid.server.bidder.loyal.LoyalBidder; | ||
import org.prebid.server.json.JacksonMapper; | ||
import org.prebid.server.spring.config.bidder.model.BidderConfigurationProperties; | ||
import org.prebid.server.spring.config.bidder.util.BidderDepsAssembler; | ||
import org.prebid.server.spring.config.bidder.util.UsersyncerCreator; | ||
import org.prebid.server.spring.env.YamlPropertySourceFactory; | ||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.boot.context.properties.ConfigurationProperties; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
import org.springframework.context.annotation.PropertySource; | ||
|
||
import jakarta.validation.constraints.NotBlank; | ||
|
||
@Configuration | ||
@PropertySource(value = "classpath:/bidder-config/loyal.yaml", factory = YamlPropertySourceFactory.class) | ||
public class LoyalConfiguration { | ||
|
||
private static final String BIDDER_NAME = "loyal"; | ||
|
||
@Bean("loyalConfigurationProperties") | ||
@ConfigurationProperties("adapters.loyal") | ||
BidderConfigurationProperties configurationProperties() { | ||
return new BidderConfigurationProperties(); | ||
} | ||
|
||
@Bean | ||
BidderDeps loaylBidderDeps(BidderConfigurationProperties loyalConfigurationProperties, | ||
@NotBlank @Value("${external-url}") String externalUrl, | ||
JacksonMapper mapper) { | ||
|
||
return BidderDepsAssembler.forBidder(BIDDER_NAME) | ||
.withConfig(loyalConfigurationProperties) | ||
.usersyncerCreator(UsersyncerCreator.create(externalUrl)) | ||
.bidderCreator(config -> new LoyalBidder(config.getEndpoint(), mapper)) | ||
.assemble(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
adapters: | ||
loyal: | ||
endpoint: "https://us-east-1.loyal.app/pserver" | ||
geoscope: | ||
- USA | ||
meta-info: | ||
maintainer-email: "hello@loyal.app" | ||
app-media-types: | ||
- banner | ||
- video | ||
- native | ||
site-media-types: | ||
- banner | ||
- video | ||
- native | ||
supported-vendors: [] | ||
vendor-id: 0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
{ | ||
"$schema": "http://json-schema.org/draft-04/schema#", | ||
"title": "Loyal Adapter Params", | ||
"description": "A schema which validates params accepted by the Loyal adapter", | ||
"type": "object", | ||
"properties": { | ||
"placementId": { | ||
"type": "string", | ||
"minLength": 1, | ||
"description": "Placement ID" | ||
}, | ||
"endpointId": { | ||
"type": "string", | ||
"minLength": 1, | ||
"description": "Endpoint ID" | ||
} | ||
}, | ||
"oneOf": [ | ||
{ | ||
"required": [ | ||
"placementId" | ||
] | ||
}, | ||
{ | ||
"required": [ | ||
"endpointId" | ||
] | ||
} | ||
] | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no sure we need this check, one of those field are required by the json scheme
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You said:
AntoxaAntoxic 2 weeks ago
the following logic is missing
and this is part of this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and you've implemented it already a few lines below
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
when I have deleted it "invalidImp goes to the results". We have to seperate invalidImp

There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so this is the Go code
as you see the imp that doesn't have the
placementId
andendpointId
fields won't be treated as invalid, but you've added the unit test that defines invalid bid as the following:So my conclusion the logic of your version of the bidder differs from the GO's version
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
okey, now its clear. I hade made wrong badImp, I was doing it in wrong way.