-
Notifications
You must be signed in to change notification settings - Fork 187
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
Yieldlab: Add Digital Service Act (DSA) support #3011
Changes from 4 commits
cc0cca6
edf9d9f
3c57c36
35f54c5
e07cb0b
0ffb3a7
358acf0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also, i don't see anything similar in GO for Does PBS-Java need to pass this debug value? Just out of interest I removed the debug part and all tests passed: Same question about and
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As far as we are concerned, it is not needed no. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As a courtesy I can fix this, but this wasn't written by us and is also out of scope. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Implementing this breaks the tests There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This code doesn't handle There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is out of scope, and I don't intend to change it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also, I don't see implementation of this part:
Will it be added later? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also, I don't see implementation of this part:
Will it be added later? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Out of scope, but.... Can i ask you to extract There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm sorry, but I must decline. Like you said it is out of scope. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,8 @@ | |
|
||
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.BidRequest; | ||
import com.iab.openrtb.request.Device; | ||
|
@@ -23,11 +25,15 @@ | |
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.bidder.yieldlab.model.YieldlabDigitalServicesActResponse; | ||
import org.prebid.server.bidder.yieldlab.model.YieldlabResponse; | ||
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.ExtRegs; | ||
import org.prebid.server.proto.openrtb.ext.request.ExtRegsDsa; | ||
import org.prebid.server.proto.openrtb.ext.request.ExtRegsDsaTransparency; | ||
import org.prebid.server.proto.openrtb.ext.request.ExtRequest; | ||
import org.prebid.server.proto.openrtb.ext.request.ExtRequestPrebid; | ||
import org.prebid.server.proto.openrtb.ext.request.ExtUser; | ||
|
@@ -41,9 +47,11 @@ | |
import java.util.ArrayList; | ||
import java.util.Calendar; | ||
import java.util.Collections; | ||
import java.util.HashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Objects; | ||
import java.util.Optional; | ||
import java.util.stream.Collectors; | ||
|
||
public class YieldlabBidder implements Bidder<Void> { | ||
|
@@ -58,6 +66,9 @@ public class YieldlabBidder implements Bidder<Void> { | |
private static final String CREATIVE_ID = "%s%s%s"; | ||
private static final String AD_SOURCE_BANNER = "<script src=\"%s\"></script>"; | ||
private static final String AD_SOURCE_URL = "https://ad.yieldlab.net/d/%s/%s/%s?%s"; | ||
private static final String TRANSPARENCY_TEMPLATE = "%s~%s"; | ||
private static final String TRANSPARENCY_TEMPLATE_PARAMS_DELIMITER = "_"; | ||
private static final String TRANSPARENCY_TEMPLATE_DELIMITER = "~~"; | ||
private static final String VAST_MARKUP = """ | ||
<VAST version="2.0"><Ad id="%s"><Wrapper> | ||
<AdSystem>Yieldlab</AdSystem> | ||
|
@@ -189,6 +200,8 @@ private String makeUrl(ExtImpYieldlab extImpYieldlab, BidRequest request) { | |
uriBuilder.addParameter("consent", consent); | ||
} | ||
|
||
extractDsaRequestParamsFromBidRequest(request).forEach(uriBuilder::addParameter); | ||
|
||
return uriBuilder.toString(); | ||
} | ||
|
||
|
@@ -231,6 +244,60 @@ private static String getConsentParameter(User user) { | |
return ObjectUtils.defaultIfNull(consent, ""); | ||
} | ||
|
||
private static Map<String, String> extractDsaRequestParamsFromBidRequest(BidRequest request) { | ||
return Optional.ofNullable(request.getRegs()) | ||
.map(Regs::getExt) | ||
.map(ExtRegs::getDsa) | ||
.map(YieldlabBidder::extractDsaRequestParamsFromDsaRegsExtension) | ||
.orElseGet(Map::of); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We are preferring to use So, please, change it with: |
||
} | ||
|
||
private static Map<String, String> extractDsaRequestParamsFromDsaRegsExtension(final ExtRegsDsa dsa) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Redundant |
||
final HashMap<String, String> dsaRequestParams = new HashMap<>(); | ||
AntoxaAntoxic marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
if (dsa.getDsaRequired() != null) { | ||
dsaRequestParams.put("dsarequired", dsa.getDsaRequired().toString()); | ||
} | ||
|
||
if (dsa.getPubRender() != null) { | ||
dsaRequestParams.put("dsapubrender", dsa.getPubRender().toString()); | ||
} | ||
|
||
if (dsa.getDataToPub() != null) { | ||
dsaRequestParams.put("dsadatatopub", dsa.getDataToPub().toString()); | ||
} | ||
AntoxaAntoxic marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
final List<ExtRegsDsaTransparency> dsaTransparency = dsa.getTransparency(); | ||
if (dsaTransparency != null && !dsaTransparency.isEmpty()) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Predicate can be simplified: |
||
dsaRequestParams.put("dsatransparency", encodeTransparenciesAsString(dsaTransparency)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
} | ||
AntoxaAntoxic marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
return dsaRequestParams; | ||
} | ||
|
||
private static String encodeTransparenciesAsString(List<ExtRegsDsaTransparency> transparencies) { | ||
return transparencies.stream() | ||
.filter(YieldlabBidder::transparencyIsValid) | ||
.map(YieldlabBidder::encodeTransparency) | ||
.collect(Collectors.joining(TRANSPARENCY_TEMPLATE_DELIMITER)); | ||
} | ||
|
||
private static boolean transparencyIsValid(ExtRegsDsaTransparency transparency) { | ||
AntoxaAntoxic marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return transparency.getDomain() != null | ||
AntoxaAntoxic marked this conversation as resolved.
Show resolved
Hide resolved
|
||
&& transparency.getDsaParams() != null | ||
&& !transparency.getDsaParams().isEmpty(); | ||
AntoxaAntoxic marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
private static String encodeTransparency(ExtRegsDsaTransparency transparency) { | ||
return TRANSPARENCY_TEMPLATE.formatted(transparency.getDomain(), | ||
encodeTransparencyParams(transparency.getDsaParams())); | ||
AntoxaAntoxic marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
private static String encodeTransparencyParams(List<Integer> dsaParams) { | ||
return dsaParams.stream().map(Objects::toString).collect(Collectors.joining( | ||
TRANSPARENCY_TEMPLATE_PARAMS_DELIMITER)); | ||
} | ||
|
||
private static MultiMap resolveHeaders(Site site, Device device, User user) { | ||
final MultiMap headers = MultiMap.caseInsensitiveMultiMap() | ||
.add(HttpUtil.ACCEPT_HEADER, HttpHeaderValues.APPLICATION_JSON); | ||
|
@@ -339,7 +406,8 @@ private Bid.BidBuilder addBidParams(YieldlabResponse yieldlabResponse, BidReques | |
.dealid(resolveNumberParameter(yieldlabResponse.getPid())) | ||
.crid(makeCreativeId(bidRequest, yieldlabResponse, matchedExtImp)) | ||
.w(resolveSizeParameter(yieldlabResponse.getAdSize(), true)) | ||
.h(resolveSizeParameter(yieldlabResponse.getAdSize(), false)); | ||
.h(resolveSizeParameter(yieldlabResponse.getAdSize(), false)) | ||
.ext(resolveExtParameter(yieldlabResponse.getDsa())); | ||
|
||
return updatedBid; | ||
} | ||
|
@@ -408,4 +476,19 @@ private String makeNurl(BidRequest bidRequest, ExtImpYieldlab extImpYieldlab, Yi | |
yieldlabResponse.getAdSize(), | ||
uriBuilder.toString().replace("?", "")); | ||
} | ||
|
||
private ObjectNode resolveExtParameter(YieldlabDigitalServicesActResponse dsa) { | ||
if (dsa == null) { | ||
return null; | ||
} | ||
final ObjectNode ext = mapper.mapper().createObjectNode(); | ||
final JsonNode dsaNode; | ||
try { | ||
dsaNode = mapper.mapper().convertValue(dsa, JsonNode.class); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
} catch (IllegalArgumentException e) { | ||
throw new PreBidException("Failed to serialize DSA object", e); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. looks like the PBS Go version has a more detailed error message Perhaps it's worth keeping it here as well Also, according to the PBS Go version the error shouldn't disrupt other bids processing, so the error has to be reported and the ext has to be null in this case. Please double-check |
||
} | ||
ext.set("dsa", dsaNode); | ||
return ext; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package org.prebid.server.bidder.yieldlab.model; | ||
|
||
import lombok.AllArgsConstructor; | ||
import lombok.Value; | ||
|
||
import java.util.List; | ||
|
||
@AllArgsConstructor(staticName = "of") | ||
@Value(staticConstructor = "of") | ||
public class YieldlabDigitalServicesActResponse { | ||
|
||
String behalf; | ||
|
||
String paid; | ||
|
||
Integer adrender; | ||
|
||
List<Transparency> transparency; | ||
|
||
@AllArgsConstructor(staticName = "of") | ||
@Value(staticConstructor = "of") | ||
public static class Transparency { | ||
String domain; | ||
List<Integer> dsaparams; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,4 +22,6 @@ public class YieldlabResponse { | |
Integer did; | ||
|
||
String pvid; | ||
|
||
YieldlabDigitalServicesActResponse dsa; | ||
} |
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.
Comparing the logic with the GO version, I don't see any sorting operations for adSlots in GO. Does PBS-Java need this?
adSlotIds.stream().sorted().collect(...)
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.
It isn't needed, no.