diff --git a/extra/modules/optable-targeting/pom.xml b/extra/modules/optable-targeting/pom.xml
index e202d7cfdd6..4853322dc0b 100644
--- a/extra/modules/optable-targeting/pom.xml
+++ b/extra/modules/optable-targeting/pom.xml
@@ -12,4 +12,12 @@
optable-targeting
Optable targeting module
+
+
+
+ io.vertx
+ vertx-junit5
+ test
+
+
diff --git a/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/config/OptableTargetingConfig.java b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/config/OptableTargetingConfig.java
index 91afba88a31..117b101e096 100644
--- a/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/config/OptableTargetingConfig.java
+++ b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/config/OptableTargetingConfig.java
@@ -4,12 +4,14 @@
import org.prebid.server.auction.privacy.enforcement.mask.UserFpdActivityMask;
import org.prebid.server.cache.PbcStorageService;
import org.prebid.server.hooks.modules.optable.targeting.model.config.OptableTargetingProperties;
+import org.prebid.server.hooks.modules.optable.targeting.v1.OptableRawAuctionRequestHook;
import org.prebid.server.hooks.modules.optable.targeting.v1.OptableTargetingAuctionResponseHook;
import org.prebid.server.hooks.modules.optable.targeting.v1.OptableTargetingModule;
import org.prebid.server.hooks.modules.optable.targeting.v1.OptableTargetingProcessedAuctionRequestHook;
import org.prebid.server.hooks.modules.optable.targeting.v1.core.Cache;
import org.prebid.server.hooks.modules.optable.targeting.v1.core.ConfigResolver;
import org.prebid.server.hooks.modules.optable.targeting.v1.core.IdsMapper;
+import org.prebid.server.hooks.modules.optable.targeting.v1.core.NetworkCall;
import org.prebid.server.hooks.modules.optable.targeting.v1.core.OptableTargeting;
import org.prebid.server.hooks.modules.optable.targeting.v1.net.APIClientImpl;
import org.prebid.server.hooks.modules.optable.targeting.v1.net.CachedAPIClient;
@@ -86,18 +88,25 @@ ConfigResolver configResolver(JsonMerger jsonMerger, OptableTargetingProperties
return new ConfigResolver(ObjectMapperProvider.mapper(), jsonMerger, globalProperties);
}
+ @Bean
+ NetworkCall networkCall(OptableTargeting optableTargeting, UserFpdActivityMask userFpdActivityMask) {
+ return new NetworkCall(optableTargeting, userFpdActivityMask);
+ }
+
@Bean
OptableTargetingModule optableTargetingModule(ConfigResolver configResolver,
- OptableTargeting optableTargeting,
- UserFpdActivityMask userFpdActivityMask,
+ NetworkCall networkCall,
JsonMerger jsonMerger,
@Value("${logging.sampling-rate:0.01}") double logSamplingRate) {
return new OptableTargetingModule(List.of(
+ new OptableRawAuctionRequestHook(
+ configResolver,
+ networkCall,
+ logSamplingRate),
new OptableTargetingProcessedAuctionRequestHook(
configResolver,
- optableTargeting,
- userFpdActivityMask,
+ networkCall,
logSamplingRate),
new OptableTargetingAuctionResponseHook(
configResolver,
diff --git a/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/model/ModuleContext.java b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/model/ModuleContext.java
index ed0264f0249..fc4122b7d48 100644
--- a/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/model/ModuleContext.java
+++ b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/model/ModuleContext.java
@@ -1,7 +1,9 @@
package org.prebid.server.hooks.modules.optable.targeting.model;
+import io.vertx.core.Future;
import lombok.Data;
import org.prebid.server.hooks.modules.optable.targeting.model.openrtb.Audience;
+import org.prebid.server.hooks.modules.optable.targeting.model.openrtb.TargetingResult;
import org.prebid.server.hooks.v1.auction.AuctionInvocationContext;
import java.util.List;
@@ -19,8 +21,19 @@ public class ModuleContext {
private long optableTargetingExecutionTime;
+ private boolean isEarlyNetworkCallEnabled = false;
+
+ private Future optableTargetingCall;
+
+ private long callTargetingAPITimestamp;
+
public static ModuleContext of(AuctionInvocationContext invocationContext) {
final ModuleContext moduleContext = (ModuleContext) invocationContext.moduleContext();
return moduleContext != null ? moduleContext : new ModuleContext();
}
+
+ public void failWithExecutionTime(long executionTime) {
+ setOptableTargetingExecutionTime(executionTime);
+ setEnrichRequestStatus(EnrichmentStatus.failure());
+ }
}
diff --git a/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/OptableHook.java b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/OptableHook.java
new file mode 100644
index 00000000000..71fd09a7c0d
--- /dev/null
+++ b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/OptableHook.java
@@ -0,0 +1,37 @@
+package org.prebid.server.hooks.modules.optable.targeting.v1;
+
+import io.vertx.core.Future;
+import org.apache.commons.lang3.StringUtils;
+import org.prebid.server.hooks.execution.v1.InvocationResultImpl;
+import org.prebid.server.hooks.modules.optable.targeting.model.ModuleContext;
+import org.prebid.server.hooks.modules.optable.targeting.model.config.OptableTargetingProperties;
+import org.prebid.server.hooks.modules.optable.targeting.v1.core.AnalyticTagsResolver;
+import org.prebid.server.hooks.v1.InvocationAction;
+import org.prebid.server.hooks.v1.InvocationResult;
+import org.prebid.server.hooks.v1.InvocationStatus;
+import org.prebid.server.hooks.v1.PayloadUpdate;
+import org.prebid.server.hooks.v1.auction.AuctionRequestPayload;
+
+public class OptableHook {
+
+ private OptableHook() {
+ }
+
+ public static boolean isTargetingPropertiesValid(OptableTargetingProperties properties) {
+ return !StringUtils.isEmpty(properties.getOrigin()) && !StringUtils.isEmpty(properties.getTenant());
+ }
+
+ public static Future> update(
+ PayloadUpdate payloadUpdate,
+ ModuleContext moduleContext) {
+
+ return Future.succeededFuture(
+ InvocationResultImpl.builder()
+ .status(InvocationStatus.success)
+ .action(InvocationAction.update)
+ .analyticsTags(AnalyticTagsResolver.toEnrichRequestAnalyticTags(moduleContext))
+ .payloadUpdate(payloadUpdate)
+ .moduleContext(moduleContext)
+ .build());
+ }
+}
diff --git a/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/OptableRawAuctionRequestHook.java b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/OptableRawAuctionRequestHook.java
new file mode 100644
index 00000000000..a96a863ba01
--- /dev/null
+++ b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/OptableRawAuctionRequestHook.java
@@ -0,0 +1,87 @@
+package org.prebid.server.hooks.modules.optable.targeting.v1;
+
+import io.vertx.core.Future;
+import org.prebid.server.hooks.execution.v1.InvocationResultImpl;
+import org.prebid.server.hooks.modules.optable.targeting.model.ModuleContext;
+import org.prebid.server.hooks.modules.optable.targeting.model.config.OptableTargetingProperties;
+import org.prebid.server.hooks.modules.optable.targeting.model.openrtb.TargetingResult;
+import org.prebid.server.hooks.modules.optable.targeting.v1.core.AnalyticTagsResolver;
+import org.prebid.server.hooks.modules.optable.targeting.v1.core.BidRequestCleaner;
+import org.prebid.server.hooks.modules.optable.targeting.v1.core.ConfigResolver;
+import org.prebid.server.hooks.modules.optable.targeting.v1.core.NetworkCall;
+import org.prebid.server.hooks.v1.InvocationAction;
+import org.prebid.server.hooks.v1.InvocationResult;
+import org.prebid.server.hooks.v1.InvocationStatus;
+import org.prebid.server.hooks.v1.auction.AuctionInvocationContext;
+import org.prebid.server.hooks.v1.auction.AuctionRequestPayload;
+import org.prebid.server.hooks.v1.auction.RawAuctionRequestHook;
+import org.prebid.server.log.ConditionalLogger;
+import org.prebid.server.log.LoggerFactory;
+
+import java.util.Objects;
+
+public class OptableRawAuctionRequestHook implements RawAuctionRequestHook {
+
+ private static final ConditionalLogger conditionalLogger = new ConditionalLogger(
+ LoggerFactory.getLogger(OptableRawAuctionRequestHook.class));
+
+ private static final String CODE = "optable-targeting-raw-auction-request-hook";
+
+ private final ConfigResolver configResolver;
+ private final NetworkCall networkCall;
+ private final double logSamplingRate;
+
+ public OptableRawAuctionRequestHook(ConfigResolver configResolver,
+ NetworkCall networkCall,
+ double logSamplingRate) {
+
+ this.configResolver = Objects.requireNonNull(configResolver);
+ this.networkCall = Objects.requireNonNull(networkCall);
+ this.logSamplingRate = logSamplingRate;
+ }
+
+ @Override
+ public Future> call(AuctionRequestPayload payload,
+ AuctionInvocationContext invocationContext) {
+
+ final OptableTargetingProperties properties = configResolver.resolve(invocationContext.accountConfig());
+ final ModuleContext moduleContext = new ModuleContext();
+ moduleContext.setEarlyNetworkCallEnabled(true);
+ moduleContext.setCallTargetingAPITimestamp(System.currentTimeMillis());
+
+ if (!OptableHook.isTargetingPropertiesValid(properties)) {
+ conditionalLogger.error(
+ "Account not properly configured: tenant and/or origin is missing.", logSamplingRate);
+
+ moduleContext.failWithExecutionTime(
+ System.currentTimeMillis() - moduleContext.getCallTargetingAPITimestamp());
+
+ return OptableHook.update(BidRequestCleaner.instance(), moduleContext);
+ }
+
+ final Future optableTargetingCall = networkCall.makeRequest(
+ payload,
+ invocationContext,
+ properties);
+
+ moduleContext.setOptableTargetingCall(optableTargetingCall);
+
+ return updateModuleContext(moduleContext);
+ }
+
+ private static Future> updateModuleContext(ModuleContext moduleContext) {
+
+ return Future.succeededFuture(
+ InvocationResultImpl.builder()
+ .status(InvocationStatus.success)
+ .action(InvocationAction.no_action)
+ .analyticsTags(AnalyticTagsResolver.toEnrichRequestAnalyticTags(moduleContext))
+ .moduleContext(moduleContext)
+ .build());
+ }
+
+ @Override
+ public String code() {
+ return CODE;
+ }
+}
diff --git a/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/OptableTargetingProcessedAuctionRequestHook.java b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/OptableTargetingProcessedAuctionRequestHook.java
index a5ad2559d40..80792de93ba 100644
--- a/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/OptableTargetingProcessedAuctionRequestHook.java
+++ b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/OptableTargetingProcessedAuctionRequestHook.java
@@ -1,31 +1,16 @@
package org.prebid.server.hooks.modules.optable.targeting.v1;
-import com.iab.openrtb.request.BidRequest;
-import com.iab.openrtb.request.Device;
-import com.iab.openrtb.request.User;
import io.vertx.core.Future;
-import org.apache.commons.lang3.StringUtils;
-import org.prebid.server.activity.Activity;
-import org.prebid.server.activity.ComponentType;
-import org.prebid.server.activity.infrastructure.ActivityInfrastructure;
-import org.prebid.server.activity.infrastructure.payload.ActivityInvocationPayload;
-import org.prebid.server.activity.infrastructure.payload.impl.ActivityInvocationPayloadImpl;
-import org.prebid.server.activity.infrastructure.payload.impl.BidRequestActivityInvocationPayload;
-import org.prebid.server.auction.model.AuctionContext;
-import org.prebid.server.auction.privacy.enforcement.mask.UserFpdActivityMask;
-import org.prebid.server.execution.timeout.Timeout;
import org.prebid.server.hooks.execution.v1.InvocationResultImpl;
import org.prebid.server.hooks.modules.optable.targeting.model.EnrichmentStatus;
import org.prebid.server.hooks.modules.optable.targeting.model.ModuleContext;
-import org.prebid.server.hooks.modules.optable.targeting.model.OptableAttributes;
import org.prebid.server.hooks.modules.optable.targeting.model.config.OptableTargetingProperties;
import org.prebid.server.hooks.modules.optable.targeting.model.openrtb.TargetingResult;
import org.prebid.server.hooks.modules.optable.targeting.v1.core.AnalyticTagsResolver;
import org.prebid.server.hooks.modules.optable.targeting.v1.core.BidRequestCleaner;
import org.prebid.server.hooks.modules.optable.targeting.v1.core.BidRequestEnricher;
import org.prebid.server.hooks.modules.optable.targeting.v1.core.ConfigResolver;
-import org.prebid.server.hooks.modules.optable.targeting.v1.core.OptableAttributesResolver;
-import org.prebid.server.hooks.modules.optable.targeting.v1.core.OptableTargeting;
+import org.prebid.server.hooks.modules.optable.targeting.v1.core.NetworkCall;
import org.prebid.server.hooks.v1.InvocationAction;
import org.prebid.server.hooks.v1.InvocationResult;
import org.prebid.server.hooks.v1.InvocationStatus;
@@ -41,23 +26,22 @@
public class OptableTargetingProcessedAuctionRequestHook implements ProcessedAuctionRequestHook {
private static final ConditionalLogger conditionalLogger = new ConditionalLogger(
- LoggerFactory.getLogger(OptableTargetingProcessedAuctionRequestHook.class));
+ LoggerFactory.getLogger(OptableRawAuctionRequestHook.class));
public static final String CODE = "optable-targeting-processed-auction-request-hook";
+ private static final String AUCTION_NOT_PROPERLY_CONFIGURED =
+ "Account not properly configured: tenant and/or origin is missing.";
+
private final ConfigResolver configResolver;
- private final OptableTargeting optableTargeting;
- private final UserFpdActivityMask userFpdActivityMask;
+ private final NetworkCall networkCall;
private final double logSamplingRate;
public OptableTargetingProcessedAuctionRequestHook(ConfigResolver configResolver,
- OptableTargeting optableTargeting,
- UserFpdActivityMask userFpdActivityMask,
+ NetworkCall networkCall,
double logSamplingRate) {
-
this.configResolver = Objects.requireNonNull(configResolver);
- this.optableTargeting = Objects.requireNonNull(optableTargeting);
- this.userFpdActivityMask = Objects.requireNonNull(userFpdActivityMask);
+ this.networkCall = Objects.requireNonNull(networkCall);
this.logSamplingRate = logSamplingRate;
}
@@ -66,80 +50,51 @@ public Future> call(AuctionRequestPayloa
AuctionInvocationContext invocationContext) {
final OptableTargetingProperties properties = configResolver.resolve(invocationContext.accountConfig());
- final ModuleContext moduleContext = new ModuleContext();
- final long callTargetingAPITimestamp = System.currentTimeMillis();
+ final ModuleContext moduleContext = ModuleContext.of(invocationContext);
- if (!isTargetingPropertiesValid(properties)) {
- conditionalLogger.error(
- "Account not properly configured: tenant and/or origin is missing.", logSamplingRate);
+ final Future optableTargetingCall = moduleContext.isEarlyNetworkCallEnabled()
+ ? moduleContext.getOptableTargetingCall()
+ : makeOptableTargetingCall(auctionRequestPayload, invocationContext, moduleContext, properties);
- moduleContext.setOptableTargetingExecutionTime(System.currentTimeMillis() - callTargetingAPITimestamp);
- moduleContext.setEnrichRequestStatus(EnrichmentStatus.failure());
+ if (optableTargetingCall == null) {
+ moduleContext.failWithExecutionTime(
+ System.currentTimeMillis() - moduleContext.getCallTargetingAPITimestamp());
return update(BidRequestCleaner.instance(), moduleContext);
}
- final BidRequest bidRequest = applyActivityRestrictions(auctionRequestPayload.bidRequest(), invocationContext);
-
- final Timeout timeout = getHookTimeout(invocationContext);
- final OptableAttributes attributes = OptableAttributesResolver.resolveAttributes(
- invocationContext.auctionContext(),
- properties.getTimeout());
-
- return optableTargeting.getTargeting(properties, bidRequest, attributes, timeout)
+ final Future> future = optableTargetingCall
.compose(targetingResult -> {
moduleContext.setOptableTargetingExecutionTime(
- System.currentTimeMillis() - callTargetingAPITimestamp);
+ System.currentTimeMillis() - moduleContext.getCallTargetingAPITimestamp());
return enrichedPayload(targetingResult, moduleContext, properties);
})
.recover(throwable -> {
- moduleContext.setOptableTargetingExecutionTime(
- System.currentTimeMillis() - callTargetingAPITimestamp);
- moduleContext.setEnrichRequestStatus(EnrichmentStatus.failure());
+ moduleContext.failWithExecutionTime(
+ System.currentTimeMillis() - moduleContext.getCallTargetingAPITimestamp());
return update(BidRequestCleaner.instance(), moduleContext);
});
- }
- private boolean isTargetingPropertiesValid(OptableTargetingProperties properties) {
- return !StringUtils.isEmpty(properties.getOrigin()) && !StringUtils.isEmpty(properties.getTenant());
+ return future;
}
- private BidRequest applyActivityRestrictions(BidRequest bidRequest,
- AuctionInvocationContext auctionInvocationContext) {
-
- final AuctionContext auctionContext = auctionInvocationContext.auctionContext();
- final ActivityInvocationPayload activityInvocationPayload = BidRequestActivityInvocationPayload.of(
- ActivityInvocationPayloadImpl.of(ComponentType.GENERAL_MODULE, OptableTargetingModule.CODE),
- bidRequest);
- final ActivityInfrastructure activityInfrastructure = auctionContext.getActivityInfrastructure();
-
- final boolean disallowTransmitUfpd = !activityInfrastructure.isAllowed(
- Activity.TRANSMIT_UFPD, activityInvocationPayload);
- final boolean disallowTransmitEids = !activityInfrastructure.isAllowed(
- Activity.TRANSMIT_EIDS, activityInvocationPayload);
- final boolean disallowTransmitGeo = !activityInfrastructure.isAllowed(
- Activity.TRANSMIT_GEO, activityInvocationPayload);
-
- return maskUserPersonalInfo(bidRequest, disallowTransmitUfpd, disallowTransmitEids, disallowTransmitGeo);
- }
-
- private BidRequest maskUserPersonalInfo(BidRequest bidRequest,
- boolean disallowTransmitUfpd,
- boolean disallowTransmitEids,
- boolean disallowTransmitGeo) {
-
- final User maskedUser = userFpdActivityMask.maskUser(
- bidRequest.getUser(), disallowTransmitUfpd, disallowTransmitEids);
- final Device maskedDevice = userFpdActivityMask.maskDevice(
- bidRequest.getDevice(), disallowTransmitUfpd, disallowTransmitGeo);
-
- return bidRequest.toBuilder()
- .user(maskedUser)
- .device(maskedDevice)
- .build();
- }
+ private Future makeOptableTargetingCall(
+ AuctionRequestPayload payload,
+ AuctionInvocationContext invocationContext,
+ ModuleContext moduleContext,
+ OptableTargetingProperties properties) {
+ moduleContext.setCallTargetingAPITimestamp(System.currentTimeMillis());
+ if (!OptableHook.isTargetingPropertiesValid(properties)) {
+ conditionalLogger.error(AUCTION_NOT_PROPERLY_CONFIGURED, logSamplingRate);
+
+ moduleContext.failWithExecutionTime(
+ System.currentTimeMillis() - moduleContext.getCallTargetingAPITimestamp());
+ return Future.failedFuture(AUCTION_NOT_PROPERLY_CONFIGURED);
+ }
- private Timeout getHookTimeout(AuctionInvocationContext invocationContext) {
- return invocationContext.timeout();
+ return networkCall.makeRequest(
+ payload,
+ invocationContext,
+ properties);
}
private Future> enrichedPayload(TargetingResult targetingResult,
diff --git a/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/NetworkCall.java b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/NetworkCall.java
new file mode 100644
index 00000000000..be7d2c42acb
--- /dev/null
+++ b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/NetworkCall.java
@@ -0,0 +1,88 @@
+package org.prebid.server.hooks.modules.optable.targeting.v1.core;
+
+import com.iab.openrtb.request.BidRequest;
+import com.iab.openrtb.request.Device;
+import com.iab.openrtb.request.User;
+import io.vertx.core.Future;
+import org.prebid.server.activity.Activity;
+import org.prebid.server.activity.ComponentType;
+import org.prebid.server.activity.infrastructure.ActivityInfrastructure;
+import org.prebid.server.activity.infrastructure.payload.ActivityInvocationPayload;
+import org.prebid.server.activity.infrastructure.payload.impl.ActivityInvocationPayloadImpl;
+import org.prebid.server.activity.infrastructure.payload.impl.BidRequestActivityInvocationPayload;
+import org.prebid.server.auction.model.AuctionContext;
+import org.prebid.server.auction.privacy.enforcement.mask.UserFpdActivityMask;
+import org.prebid.server.execution.timeout.Timeout;
+import org.prebid.server.hooks.modules.optable.targeting.model.OptableAttributes;
+import org.prebid.server.hooks.modules.optable.targeting.model.config.OptableTargetingProperties;
+import org.prebid.server.hooks.modules.optable.targeting.model.openrtb.TargetingResult;
+import org.prebid.server.hooks.modules.optable.targeting.v1.OptableTargetingModule;
+import org.prebid.server.hooks.v1.auction.AuctionInvocationContext;
+import org.prebid.server.hooks.v1.auction.AuctionRequestPayload;
+
+import java.util.Objects;
+
+public class NetworkCall {
+
+ private final OptableTargeting optableTargeting;
+ private final UserFpdActivityMask userFpdActivityMask;
+
+ public NetworkCall(OptableTargeting optableTargeting, UserFpdActivityMask userFpdActivityMask) {
+
+ this.optableTargeting = Objects.requireNonNull(optableTargeting);
+ this.userFpdActivityMask = Objects.requireNonNull(userFpdActivityMask);
+ }
+
+ public Future makeRequest(AuctionRequestPayload payload,
+ AuctionInvocationContext invocationContext,
+ OptableTargetingProperties properties) {
+
+ final BidRequest bidRequest = applyActivityRestrictions(payload.bidRequest(), invocationContext);
+
+ final Timeout timeout = getHookTimeout(invocationContext);
+ final OptableAttributes attributes = OptableAttributesResolver.resolveAttributes(
+ invocationContext.auctionContext(),
+ properties.getTimeout());
+
+ return optableTargeting.getTargeting(properties, bidRequest, attributes, timeout);
+ }
+
+ private static Timeout getHookTimeout(AuctionInvocationContext invocationContext) {
+ return invocationContext.timeout();
+ }
+
+ private BidRequest applyActivityRestrictions(BidRequest bidRequest,
+ AuctionInvocationContext auctionInvocationContext) {
+
+ final AuctionContext auctionContext = auctionInvocationContext.auctionContext();
+ final ActivityInvocationPayload activityInvocationPayload = BidRequestActivityInvocationPayload.of(
+ ActivityInvocationPayloadImpl.of(ComponentType.GENERAL_MODULE, OptableTargetingModule.CODE),
+ bidRequest);
+ final ActivityInfrastructure activityInfrastructure = auctionContext.getActivityInfrastructure();
+
+ final boolean disallowTransmitUfpd = !activityInfrastructure.isAllowed(
+ Activity.TRANSMIT_UFPD, activityInvocationPayload);
+ final boolean disallowTransmitEids = !activityInfrastructure.isAllowed(
+ Activity.TRANSMIT_EIDS, activityInvocationPayload);
+ final boolean disallowTransmitGeo = !activityInfrastructure.isAllowed(
+ Activity.TRANSMIT_GEO, activityInvocationPayload);
+
+ return maskUserPersonalInfo(bidRequest, disallowTransmitUfpd, disallowTransmitEids, disallowTransmitGeo);
+ }
+
+ private BidRequest maskUserPersonalInfo(BidRequest bidRequest,
+ boolean disallowTransmitUfpd,
+ boolean disallowTransmitEids,
+ boolean disallowTransmitGeo) {
+
+ final User maskedUser = userFpdActivityMask.maskUser(
+ bidRequest.getUser(), disallowTransmitUfpd, disallowTransmitEids);
+ final Device maskedDevice = userFpdActivityMask.maskDevice(
+ bidRequest.getDevice(), disallowTransmitUfpd, disallowTransmitGeo);
+
+ return bidRequest.toBuilder()
+ .user(maskedUser)
+ .device(maskedDevice)
+ .build();
+ }
+}
diff --git a/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/OptableAttributesResolver.java b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/OptableAttributesResolver.java
index 7f2aad0657d..8009a9f2ff5 100644
--- a/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/OptableAttributesResolver.java
+++ b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/OptableAttributesResolver.java
@@ -1,11 +1,16 @@
package org.prebid.server.hooks.modules.optable.targeting.v1.core;
+import com.iab.openrtb.request.BidRequest;
import com.iab.openrtb.request.Device;
+import com.iab.openrtb.request.Regs;
+import com.iab.openrtb.request.User;
import org.apache.commons.collections4.SetUtils;
+import org.apache.commons.lang3.StringUtils;
import org.prebid.server.auction.gpp.model.GppContext;
import org.prebid.server.auction.model.AuctionContext;
import org.prebid.server.hooks.modules.optable.targeting.model.OptableAttributes;
-import org.prebid.server.privacy.gdpr.model.TcfContext;
+import org.prebid.server.proto.openrtb.ext.request.ExtRegs;
+import org.prebid.server.proto.openrtb.ext.request.ExtUser;
import java.util.ArrayList;
import java.util.List;
@@ -17,18 +22,33 @@ private OptableAttributesResolver() {
}
public static OptableAttributes resolveAttributes(AuctionContext auctionContext, Long timeout) {
- final TcfContext tcfContext = auctionContext.getPrivacyContext().getTcfContext();
final GppContext.Scope gppScope = auctionContext.getGppContext().scope();
+ final BidRequest bidRequest = auctionContext.getBidRequest();
+ final Optional regs = Optional.ofNullable(bidRequest.getRegs());
+ final Integer gdpr = regs
+ .map(Regs::getGdpr)
+ .orElseGet(() -> regs.map(Regs::getExt)
+ .map(ExtRegs::getGdpr)
+ .orElse(null));
+
final OptableAttributes.OptableAttributesBuilder builder = OptableAttributes.builder()
.ips(resolveIp(auctionContext))
.userAgent(resolveUserAgent(auctionContext))
.timeout(timeout);
- if (tcfContext.isConsentValid()) {
- builder
- .gdprApplies(tcfContext.isInGdprScope())
- .gdprConsent(tcfContext.getConsentString());
+ if (gdpr != null && gdpr > 0) {
+ final Optional user = Optional.ofNullable(bidRequest.getUser());
+ final String consent = user.map(User::getConsent)
+ .orElseGet(() -> user.map(User::getExt)
+ .map(ExtUser::getConsent)
+ .orElse(null));
+
+ if (StringUtils.isNotEmpty(consent)) {
+ builder
+ .gdprApplies(true)
+ .gdprConsent(consent);
+ }
}
if (gppScope.getGppModel() != null) {
diff --git a/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/BaseOptableTest.java b/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/BaseOptableTest.java
index 99f24ea4bc5..90f2008cec7 100644
--- a/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/BaseOptableTest.java
+++ b/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/BaseOptableTest.java
@@ -103,6 +103,14 @@ protected BidRequest givenBidRequestWithUserEids(List eids) {
.build();
}
+ protected BidRequest givenBidRequestWithUser(User user) {
+ return BidRequest.builder()
+ .user(user)
+ .device(givenDevice())
+ .cur(List.of("USD"))
+ .build();
+ }
+
protected BidRequest givenBidRequestWithUserData(List data) {
return BidRequest.builder()
.user(givenUserWithData(data))
@@ -254,4 +262,8 @@ protected OptableTargetingProperties givenOptableTargetingProperties(String key,
protected Query givenQuery() {
return Query.of("?que", "ry");
}
+
+ protected ObjectNode givenAccountConfig(String key, String tenant, String origin, boolean cacheEnabled) {
+ return mapper.valueToTree(givenOptableTargetingProperties(key, tenant, origin, cacheEnabled));
+ }
}
diff --git a/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/OptableRawAuctionRequestHookTest.java b/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/OptableRawAuctionRequestHookTest.java
new file mode 100644
index 00000000000..00a0bbf77ee
--- /dev/null
+++ b/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/OptableRawAuctionRequestHookTest.java
@@ -0,0 +1,127 @@
+package org.prebid.server.hooks.modules.optable.targeting.v1;
+
+import io.vertx.core.Future;
+import io.vertx.junit5.VertxExtension;
+import io.vertx.junit5.VertxTestContext;
+import lombok.SneakyThrows;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoSettings;
+import org.mockito.quality.Strictness;
+import org.prebid.server.activity.infrastructure.ActivityInfrastructure;
+import org.prebid.server.auction.privacy.enforcement.mask.UserFpdActivityMask;
+import org.prebid.server.execution.timeout.Timeout;
+import org.prebid.server.hooks.modules.optable.targeting.model.ModuleContext;
+import org.prebid.server.hooks.modules.optable.targeting.v1.core.ConfigResolver;
+import org.prebid.server.hooks.modules.optable.targeting.v1.core.NetworkCall;
+import org.prebid.server.hooks.modules.optable.targeting.v1.core.OptableTargeting;
+import org.prebid.server.hooks.v1.InvocationResult;
+import org.prebid.server.hooks.v1.auction.AuctionInvocationContext;
+import org.prebid.server.hooks.v1.auction.AuctionRequestPayload;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.Mockito.when;
+
+@MockitoSettings(strictness = Strictness.LENIENT)
+@ExtendWith(VertxExtension.class)
+public class OptableRawAuctionRequestHookTest extends BaseOptableTest {
+
+ @Mock
+ private OptableTargeting optableTargeting;
+ @Mock
+ private UserFpdActivityMask userFpdActivityMask;
+ @Mock
+ private AuctionRequestPayload auctionRequestPayload;
+ @Mock
+ private ActivityInfrastructure activityInfrastructure;
+ @Mock
+ private AuctionInvocationContext invocationContext;
+ @Mock
+ private Timeout timeout;
+
+ private ConfigResolver configResolver;
+ private NetworkCall networkCall;
+ private OptableRawAuctionRequestHook target;
+
+ @BeforeEach
+ public void setUp() {
+ when(userFpdActivityMask.maskDevice(any(), anyBoolean(), anyBoolean()))
+ .thenAnswer(answer -> answer.getArgument(0));
+ configResolver = new ConfigResolver(mapper, jsonMerger, givenOptableTargetingProperties(false));
+ networkCall = new NetworkCall(optableTargeting, userFpdActivityMask);
+ target = new OptableRawAuctionRequestHook(configResolver, networkCall, 0.01);
+ when(invocationContext.auctionContext()).thenReturn(givenAuctionContext(activityInfrastructure, timeout));
+ when(invocationContext.timeout()).thenReturn(timeout);
+ when(activityInfrastructure.isAllowed(any(), any())).thenReturn(true);
+ when(timeout.remaining()).thenReturn(1000L);
+ }
+
+ @Test
+ public void shouldHaveRightCode() {
+ // when and then
+ assertThat(target.code()).isEqualTo("optable-targeting-raw-auction-request-hook");
+ }
+
+ @SneakyThrows
+ @Test
+ public void shouldInjectEarlyNetworkCallToModuleContext(VertxTestContext vertxTestContext) {
+ // given
+ when(invocationContext.accountConfig())
+ .thenReturn(givenAccountConfig("key", "tenant", "origin", true));
+ when(auctionRequestPayload.bidRequest()).thenReturn(givenBidRequest());
+ when(optableTargeting.getTargeting(any(), any(), any(), any()))
+ .thenReturn(Future.succeededFuture(givenTargetingResult()));
+
+ // when
+ final Future> result =
+ target.call(auctionRequestPayload, invocationContext);
+
+ // then
+ assertThat(result).isNotNull();
+ result.map(res -> (ModuleContext) res.moduleContext())
+ .compose(ModuleContext::getOptableTargetingCall)
+ .onComplete(call -> {
+ vertxTestContext.verify(() -> {
+ assertThat(call.result()).isNotNull();
+ });
+ vertxTestContext.completeNow();
+ });
+ }
+
+ @SneakyThrows
+ @Test
+ public void shouldNotInjectEarlyNetworkCallToModuleContextWhenOriginIsAbsentInAccountConfiguration(
+ VertxTestContext vertxTestContext) {
+
+ // given
+ when(invocationContext.accountConfig())
+ .thenReturn(givenAccountConfig("key", "tenant", null, true));
+ when(auctionRequestPayload.bidRequest()).thenReturn(givenBidRequest());
+ when(optableTargeting.getTargeting(any(), any(), any(), any()))
+ .thenReturn(Future.succeededFuture(givenTargetingResult()));
+
+ configResolver = new ConfigResolver(
+ mapper, jsonMerger, givenOptableTargetingProperties("key", "tenant", null, true));
+ target = new OptableRawAuctionRequestHook(configResolver, networkCall, 0.01);
+
+ // when
+ final Future> result =
+ target.call(auctionRequestPayload, invocationContext);
+
+ // then
+ assertThat(result).isNotNull();
+ result.map(res -> (ModuleContext) res.moduleContext())
+ .onComplete(cxt -> {
+ vertxTestContext.verify(() -> {
+ final ModuleContext moduleContext = cxt.result();
+ assertThat(moduleContext.getOptableTargetingCall()).isNull();
+ assertThat(moduleContext.isEarlyNetworkCallEnabled()).isTrue();
+ });
+ vertxTestContext.completeNow();
+ });
+ }
+}
diff --git a/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/OptableTargetingProcessedAuctionRequestHookTest.java b/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/OptableTargetingProcessedAuctionRequestHookTest.java
index 008262b8a3e..190004eb758 100644
--- a/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/OptableTargetingProcessedAuctionRequestHookTest.java
+++ b/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/OptableTargetingProcessedAuctionRequestHookTest.java
@@ -17,6 +17,7 @@
import org.prebid.server.hooks.modules.optable.targeting.model.ModuleContext;
import org.prebid.server.hooks.modules.optable.targeting.model.Status;
import org.prebid.server.hooks.modules.optable.targeting.v1.core.ConfigResolver;
+import org.prebid.server.hooks.modules.optable.targeting.v1.core.NetworkCall;
import org.prebid.server.hooks.modules.optable.targeting.v1.core.OptableTargeting;
import org.prebid.server.hooks.v1.InvocationAction;
import org.prebid.server.hooks.v1.InvocationResult;
@@ -41,8 +42,6 @@ public class OptableTargetingProcessedAuctionRequestHookTest extends BaseOptable
@Mock
private UserFpdActivityMask userFpdActivityMask;
- private OptableTargetingProcessedAuctionRequestHook target;
-
@Mock
private AuctionRequestPayload auctionRequestPayload;
@@ -55,16 +54,17 @@ public class OptableTargetingProcessedAuctionRequestHookTest extends BaseOptable
@Mock
private Timeout timeout;
+ private NetworkCall networkCall;
+
+ private OptableTargetingProcessedAuctionRequestHook target;
+
@BeforeEach
public void setUp() {
when(userFpdActivityMask.maskDevice(any(), anyBoolean(), anyBoolean()))
.thenAnswer(answer -> answer.getArgument(0));
configResolver = new ConfigResolver(mapper, jsonMerger, givenOptableTargetingProperties(false));
- target = new OptableTargetingProcessedAuctionRequestHook(
- configResolver,
- optableTargeting,
- userFpdActivityMask,
- 0.01);
+ networkCall = new NetworkCall(optableTargeting, userFpdActivityMask);
+ target = new OptableTargetingProcessedAuctionRequestHook(configResolver, networkCall, 0.01);
when(invocationContext.accountConfig()).thenReturn(givenAccountConfig(true));
when(invocationContext.auctionContext()).thenReturn(givenAuctionContext(activityInfrastructure, timeout));
@@ -131,6 +131,40 @@ public void shouldReturnResultWithUpdateActionWhenOptableTargetingReturnTargetin
assertThat(bidRequest.getUser().getData().getFirst().getSegment().getFirst().getId()).isEqualTo("id");
}
+ @Test
+ public void shouldReturnResultWithUpdateActionWhenEarlyOptableCallIsEnabled() {
+ // given
+ final ModuleContext moduleContext = new ModuleContext();
+ moduleContext.setEarlyNetworkCallEnabled(true);
+ when(optableTargeting.getTargeting(any(), any(), any(), any()))
+ .thenReturn(Future.succeededFuture(givenTargetingResult()));
+ when(invocationContext.moduleContext()).thenReturn(moduleContext);
+ when(auctionRequestPayload.bidRequest()).thenReturn(givenBidRequest());
+ moduleContext.setOptableTargetingCall(
+ networkCall.makeRequest(auctionRequestPayload, invocationContext, givenOptableTargetingProperties(
+ "key", "tenant", "origin", false)));
+
+ // when
+ final Future> future = target.call(auctionRequestPayload,
+ invocationContext);
+
+ // then
+ assertThat(future).isNotNull();
+ assertThat(future.succeeded()).isTrue();
+
+ final InvocationResult result = future.result();
+ assertThat(result).isNotNull();
+ assertThat(result.status()).isEqualTo(InvocationStatus.success);
+ assertThat(result.action()).isEqualTo(InvocationAction.update);
+ assertThat(result.errors()).isNull();
+ final BidRequest bidRequest = result
+ .payloadUpdate()
+ .apply(AuctionRequestPayloadImpl.of(givenBidRequest()))
+ .bidRequest();
+ assertThat(bidRequest.getUser().getEids().getFirst().getUids().getFirst().getId()).isEqualTo("id");
+ assertThat(bidRequest.getUser().getData().getFirst().getSegment().getFirst().getId()).isEqualTo("id");
+ }
+
@Test
public void shouldReturnFailWhenOriginIsAbsentInAccountConfiguration() {
// given
@@ -138,11 +172,7 @@ public void shouldReturnFailWhenOriginIsAbsentInAccountConfiguration() {
mapper,
jsonMerger,
givenOptableTargetingProperties("key", "tenant", null, false));
- target = new OptableTargetingProcessedAuctionRequestHook(
- configResolver,
- optableTargeting,
- userFpdActivityMask,
- 0.01);
+ target = new OptableTargetingProcessedAuctionRequestHook(configResolver, networkCall, 0.01);
when(invocationContext.accountConfig())
.thenReturn(givenAccountConfig("key", "tenant", null, true));
@@ -170,11 +200,7 @@ public void shouldReturnFailWhenTenantIsAbsentInAccountConfiguration() {
mapper,
jsonMerger,
givenOptableTargetingProperties("key", null, "origin", false));
- target = new OptableTargetingProcessedAuctionRequestHook(
- configResolver,
- optableTargeting,
- userFpdActivityMask,
- 0.01);
+ target = new OptableTargetingProcessedAuctionRequestHook(configResolver, networkCall, 0.01);
when(invocationContext.accountConfig())
.thenReturn(givenAccountConfig("key", null, null, true));
@@ -249,8 +275,4 @@ public void shouldReturnResultWithUpdateWhenOptableTargetingDoesntReturnResult()
private ObjectNode givenAccountConfig(boolean cacheEnabled) {
return givenAccountConfig("key", "tenant", "origin", cacheEnabled);
}
-
- private ObjectNode givenAccountConfig(String key, String tenant, String origin, boolean cacheEnabled) {
- return mapper.valueToTree(givenOptableTargetingProperties(key, tenant, origin, cacheEnabled));
- }
}
diff --git a/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/OptableAttributesResolverTest.java b/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/OptableAttributesResolverTest.java
index de2c01948fb..9621758cab0 100644
--- a/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/OptableAttributesResolverTest.java
+++ b/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/OptableAttributesResolverTest.java
@@ -2,6 +2,8 @@
import com.iab.gpp.encoder.GppModel;
import com.iab.openrtb.request.BidRequest;
+import com.iab.openrtb.request.Regs;
+import com.iab.openrtb.request.User;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@@ -15,6 +17,8 @@
import org.prebid.server.privacy.gdpr.model.TcfContext;
import org.prebid.server.privacy.model.Privacy;
import org.prebid.server.privacy.model.PrivacyContext;
+import org.prebid.server.proto.openrtb.ext.request.ExtRegs;
+import org.prebid.server.proto.openrtb.ext.request.ExtUser;
import java.util.List;
import java.util.Set;
@@ -42,15 +46,32 @@ public void setUp() {
}
@Test
- public void shouldResolveTcfAttributesWhenConsentIsValid() {
+ public void shouldResolveGdprAttributesForORTB26WhenConsentIsValid() {
// given
final GppModel gppModel = mock();
- when(tcfContext.isConsentValid()).thenReturn(true);
- when(tcfContext.isInGdprScope()).thenReturn(true);
- when(tcfContext.getConsentString()).thenReturn("consent");
when(gppModel.encode()).thenReturn("consent");
when(gppContext.scope()).thenReturn(GppContext.Scope.of(gppModel, Set.of(1)));
- final AuctionContext auctionContext = givenAuctionContext(givenBidRequest(), tcfContext, gppContext);
+ final AuctionContext auctionContext =
+ givenAuctionContext(givenBidRequestWithGdprORTB26(true, "consent"), tcfContext, gppContext);
+
+ // when
+ final OptableAttributes result = OptableAttributesResolver.resolveAttributes(
+ auctionContext, properties.getTimeout());
+
+ // then
+ assertThat(result).isNotNull()
+ .returns(true, OptableAttributes::isGdprApplies)
+ .returns("consent", OptableAttributes::getGdprConsent);
+ }
+
+ @Test
+ public void shouldResolveGdprAttributesForORTB25WhenConsentIsValid() {
+ // given
+ final GppModel gppModel = mock();
+ when(gppModel.encode()).thenReturn("consent");
+ when(gppContext.scope()).thenReturn(GppContext.Scope.of(gppModel, Set.of(1)));
+ final AuctionContext auctionContext =
+ givenAuctionContext(givenBidRequestWithGdprORTB25(true, "consent"), tcfContext, gppContext);
// when
final OptableAttributes result = OptableAttributesResolver.resolveAttributes(
@@ -62,6 +83,34 @@ public void shouldResolveTcfAttributesWhenConsentIsValid() {
.returns("consent", OptableAttributes::getGdprConsent);
}
+ private BidRequest givenBidRequestWithGdprORTB26(boolean isGdprEnabled, String consent) {
+ final User user = User.builder()
+ .consent(consent)
+ .build();
+
+ return BidRequest.builder()
+ .user(user)
+ .regs(Regs.builder()
+ .gdpr(isGdprEnabled ? 1 : 0)
+ .build())
+ .build();
+ }
+
+ private BidRequest givenBidRequestWithGdprORTB25(boolean isGdprEnabled, String consent) {
+ final User user = User.builder()
+ .ext(ExtUser.builder()
+ .consent(consent)
+ .build())
+ .build();
+
+ return BidRequest.builder()
+ .user(user)
+ .regs(Regs.builder()
+ .ext(ExtRegs.of(isGdprEnabled ? 1 : 0, null, null, null))
+ .build())
+ .build();
+ }
+
@Test
public void shouldNotResolveTcfAttributesWhenConsentIsNotValid() {
// given
diff --git a/sample/configs/prebid-config-with-optable-old.yaml b/sample/configs/prebid-config-with-optable-old.yaml
new file mode 100644
index 00000000000..9efe5a34e5c
--- /dev/null
+++ b/sample/configs/prebid-config-with-optable-old.yaml
@@ -0,0 +1,53 @@
+status-response: "ok"
+adapters:
+ appnexus:
+ enabled: true
+ ix:
+ enabled: true
+ openx:
+ enabled: true
+ pubmatic:
+ enabled: true
+ rubicon:
+ enabled: true
+ improvedigital:
+ enabled: true
+ colossus:
+ enabled: true
+ triplelift:
+ enabled: true
+metrics:
+ prefix: prebid
+cache:
+ scheme: http
+ host: localhost
+ path: /cache
+ query: uuid=
+settings:
+ enforce-valid-account: false
+ generate-storedrequest-bidrequest-id: true
+ filesystem:
+ settings-filename: sample/configs/sample-app-settings-optable-old.yaml
+ stored-requests-dir: sample
+ stored-imps-dir: sample
+ stored-responses-dir: sample/stored
+ categories-dir:
+gdpr:
+ default-value: 1
+ vendorlist:
+ v2:
+ cache-dir: /var/tmp/vendor2
+ v3:
+ cache-dir: /var/tmp/vendor3
+admin-endpoints:
+ logging-changelevel:
+ enabled: true
+ path: /logging/changelevel
+ on-application-port: true
+ protected: false
+hooks:
+ optable-targeting:
+ enabled: true
+ modules:
+ optable-targeting:
+ api-endpoint: https://na.edge.optable.co/v2/targeting?t={{TENANT}}&o={{ORIGIN}}
diff --git a/sample/configs/sample-app-settings-optable-old.yaml b/sample/configs/sample-app-settings-optable-old.yaml
new file mode 100644
index 00000000000..7a533da3697
--- /dev/null
+++ b/sample/configs/sample-app-settings-optable-old.yaml
@@ -0,0 +1,63 @@
+accounts:
+ - id: 1
+ status: active
+ auction:
+ price-granularity: low
+ privacy:
+ ccpa:
+ enabled: true
+ gdpr:
+ enabled: true
+ cookie-sync:
+ default-limit: 8
+ max-limit: 15
+ coop-sync:
+ default: true
+ analytics:
+ allow-client-details: true
+ hooks:
+ modules:
+ optable-targeting:
+ api-key: key
+ tenant: optable
+ origin: web-sdk-demo
+ ppid-mapping: { "pubcid.org": "c" }
+ adserver-targeting: true
+ cache:
+ enabled: false
+ ttlseconds: 86400
+ execution-plan:
+ {
+ "endpoints": {
+ "/openrtb2/auction": {
+ "stages": {
+ "processed-auction-request": {
+ "groups": [
+ {
+ "timeout": 600,
+ "hook-sequence": [
+ {
+ "module-code": "optable-targeting",
+ "hook-impl-code": "optable-targeting-processed-auction-request-hook"
+ }
+ ]
+ }
+ ]
+ },
+ "auction-response": {
+ "groups": [
+ {
+ "timeout": 10,
+ "hook-sequence": [
+ {
+ "module-code": "optable-targeting",
+ "hook-impl-code": "optable-targeting-auction-response-hook"
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
diff --git a/sample/configs/sample-app-settings-optable.yaml b/sample/configs/sample-app-settings-optable.yaml
index 7a533da3697..571ad0a5a97 100644
--- a/sample/configs/sample-app-settings-optable.yaml
+++ b/sample/configs/sample-app-settings-optable.yaml
@@ -31,6 +31,19 @@ accounts:
"endpoints": {
"/openrtb2/auction": {
"stages": {
+ "raw-auction-request": {
+ "groups": [
+ {
+ "timeout": 1000,
+ "hook-sequence": [
+ {
+ "module-code": "optable-targeting",
+ "hook-impl-code": "optable-targeting-raw-auction-request-hook"
+ }
+ ]
+ }
+ ]
+ },
"processed-auction-request": {
"groups": [
{