Skip to content

Commit

Permalink
Merge branch 'prebid:master' into preciso_bdr_initial
Browse files Browse the repository at this point in the history
  • Loading branch information
PrecisoSRL authored Aug 3, 2023
2 parents ca7cf32 + 78ae6b4 commit 88f1fe1
Show file tree
Hide file tree
Showing 121 changed files with 9,388 additions and 1,442 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,38 +5,35 @@

import java.util.List;
import java.util.Objects;
import java.util.Optional;

public class ActivityConfiguration {
public class ActivityController {

private final boolean allowByDefault;
private final List<Rule> rules;

private ActivityConfiguration(boolean allowByDefault, List<Rule> rules) {
private ActivityController(boolean allowByDefault, List<Rule> rules) {
this.allowByDefault = allowByDefault;
this.rules = Objects.requireNonNull(rules);
}

public static ActivityConfiguration of(boolean allowByDefault, List<Rule> rules) {
return new ActivityConfiguration(allowByDefault, rules);
public static ActivityController of(boolean allowByDefault, List<Rule> rules) {
return new ActivityController(allowByDefault, rules);
}

public ActivityCallResult isAllowed(ActivityCallPayload activityCallPayload) {
int processedRulesCount = 0;
Rule matchedRule = null;
boolean result = allowByDefault;

for (Rule rule : rules) {
processedRulesCount++;
if (rule.matches(activityCallPayload)) {
matchedRule = rule;

final Rule.Result ruleResult = rule.proceed(activityCallPayload);
if (ruleResult != Rule.Result.ABSTAIN) {
result = ruleResult == Rule.Result.ALLOW;
break;
}
}

return ActivityCallResult.of(
Optional.ofNullable(matchedRule)
.map(Rule::allowed)
.orElse(allowByDefault),
processedRulesCount);
return ActivityCallResult.of(result, processedRulesCount);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,31 +15,31 @@ public class ActivityInfrastructure {
public static final boolean ALLOW_ACTIVITY_BY_DEFAULT = true;

private final String accountId;
private final Map<Activity, ActivityConfiguration> activitiesConfigurations;
private final Map<Activity, ActivityController> activitiesControllers;
private final TraceLevel traceLevel;
private final Metrics metrics;

public ActivityInfrastructure(String accountId,
Map<Activity, ActivityConfiguration> activitiesConfigurations,
Map<Activity, ActivityController> activitiesControllers,
TraceLevel traceLevel,
Metrics metrics) {

validate(activitiesConfigurations);
validate(activitiesControllers);

this.accountId = accountId;
this.activitiesConfigurations = activitiesConfigurations;
this.activitiesControllers = activitiesControllers;
this.traceLevel = Objects.requireNonNull(traceLevel);
this.metrics = Objects.requireNonNull(metrics);
}

private static void validate(Map<Activity, ActivityConfiguration> activitiesConfigurations) {
if (activitiesConfigurations == null || activitiesConfigurations.size() != Activity.values().length) {
throw new AssertionError("Activities configuration must include all possible activities.");
private static void validate(Map<Activity, ActivityController> activitiesControllers) {
if (activitiesControllers == null || activitiesControllers.size() != Activity.values().length) {
throw new AssertionError("Activities controllers must include all possible activities.");
}
}

public boolean isAllowed(Activity activity, ActivityCallPayload activityCallPayload) {
final ActivityCallResult result = activitiesConfigurations.get(activity).isAllowed(activityCallPayload);
final ActivityCallResult result = activitiesControllers.get(activity).isAllowed(activityCallPayload);
updateMetrics(activity, activityCallPayload, result);
return result.isAllowed();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package org.prebid.server.activity.infrastructure.creator;

import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
import lombok.Value;
import org.prebid.server.activity.Activity;
import org.prebid.server.activity.infrastructure.privacy.PrivacyModuleQualifier;
import org.prebid.server.auction.gpp.model.GppContext;
import org.prebid.server.settings.model.activity.privacy.AccountPrivacyModuleConfig;

import java.util.EnumSet;
import java.util.Map;
import java.util.Set;

@Value(staticConstructor = "of")
public class ActivityControllerCreationContext {

Activity activity;

Map<PrivacyModuleQualifier, AccountPrivacyModuleConfig> privacyModulesConfigs;

@Getter(AccessLevel.NONE)
@Setter(AccessLevel.NONE)
Set<PrivacyModuleQualifier> usedPrivacyModules = EnumSet.noneOf(PrivacyModuleQualifier.class);

GppContext gppContext;

public boolean isUsed(PrivacyModuleQualifier qualifier) {
return usedPrivacyModules.contains(qualifier);
}

public void use(PrivacyModuleQualifier qualifier) {
usedPrivacyModules.add(qualifier);
}
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
package org.prebid.server.activity.infrastructure.creator;

import io.vertx.core.logging.Logger;
import io.vertx.core.logging.LoggerFactory;
import org.apache.commons.collections4.ListUtils;
import org.prebid.server.activity.Activity;
import org.prebid.server.activity.infrastructure.ActivityConfiguration;
import org.prebid.server.activity.infrastructure.ActivityController;
import org.prebid.server.activity.infrastructure.ActivityInfrastructure;
import org.prebid.server.activity.infrastructure.privacy.PrivacyModuleQualifier;
import org.prebid.server.activity.infrastructure.rule.Rule;
import org.prebid.server.auction.gpp.model.GppContext;
import org.prebid.server.metric.MetricName;
import org.prebid.server.metric.Metrics;
import org.prebid.server.proto.openrtb.ext.request.TraceLevel;
import org.prebid.server.settings.model.Account;
import org.prebid.server.settings.model.AccountPrivacyConfig;
import org.prebid.server.settings.model.activity.AccountActivityConfiguration;
import org.prebid.server.settings.model.activity.privacy.AccountPrivacyModuleConfig;

import java.util.Arrays;
import java.util.Collections;
Expand All @@ -19,12 +24,15 @@
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.BinaryOperator;
import java.util.function.Supplier;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors;

public class ActivityInfrastructureCreator {

private static final Logger logger = LoggerFactory.getLogger(ActivityInfrastructureCreator.class);

private final ActivityRuleFactory activityRuleFactory;
private final Metrics metrics;

Expand All @@ -41,40 +49,67 @@ public ActivityInfrastructure create(Account account, GppContext gppContext, Tra
metrics);
}

Map<Activity, ActivityConfiguration> parse(Account account, GppContext gppContext) {
final Map<Activity, AccountActivityConfiguration> activitiesConfiguration =
Optional.ofNullable(account)
.map(Account::getPrivacy)
.map(AccountPrivacyConfig::getActivities)
.orElse(Collections.emptyMap());
Map<Activity, ActivityController> parse(Account account, GppContext gppContext) {
final Optional<AccountPrivacyConfig> accountPrivacyConfig = Optional.ofNullable(account.getPrivacy());

final Map<Activity, AccountActivityConfiguration> activitiesConfiguration = accountPrivacyConfig
.map(AccountPrivacyConfig::getActivities)
.orElseGet(Collections::emptyMap);
final Map<PrivacyModuleQualifier, AccountPrivacyModuleConfig> modulesConfigs = accountPrivacyConfig
.map(AccountPrivacyConfig::getModules)
.orElseGet(Collections::emptyList)
.stream()
.collect(Collectors.toMap(
AccountPrivacyModuleConfig::getCode,
UnaryOperator.identity(),
takeFirstAndLogDuplicates(account.getId())));

return Arrays.stream(Activity.values())
.collect(Collectors.toMap(
UnaryOperator.identity(),
activity -> from(activitiesConfiguration.get(activity), gppContext),
activity -> from(activity, activitiesConfiguration.get(activity), modulesConfigs, gppContext),
(oldValue, newValue) -> newValue,
enumMapFactory()));
}

private ActivityConfiguration from(AccountActivityConfiguration activityConfiguration, GppContext gppContext) {
private BinaryOperator<AccountPrivacyModuleConfig> takeFirstAndLogDuplicates(String accountId) {
return (first, second) -> {
logger.warn("Duplicate configuration found for privacy module %s for account %s"
.formatted(second.getCode(), accountId));
metrics.updateAlertsMetrics(MetricName.general);

return first;
};
}

private ActivityController from(Activity activity,
AccountActivityConfiguration activityConfiguration,
Map<PrivacyModuleQualifier, AccountPrivacyModuleConfig> modulesConfigs,
GppContext gppContext) {

if (activityConfiguration == null) {
return ActivityConfiguration.of(ActivityInfrastructure.ALLOW_ACTIVITY_BY_DEFAULT, Collections.emptyList());
return ActivityController.of(ActivityInfrastructure.ALLOW_ACTIVITY_BY_DEFAULT, Collections.emptyList());
}

final ActivityControllerCreationContext creationContext = ActivityControllerCreationContext.of(
activity,
modulesConfigs,
gppContext);

final boolean allow = allowFromConfig(activityConfiguration.getAllow());
final List<Rule> rules = ListUtils.emptyIfNull(activityConfiguration.getRules()).stream()
.filter(Objects::nonNull)
.map(ruleConfiguration -> activityRuleFactory.from(ruleConfiguration, gppContext))
.map(ruleConfiguration -> activityRuleFactory.from(ruleConfiguration, creationContext))
.toList();

return ActivityConfiguration.of(allow, rules);
return ActivityController.of(allow, rules);
}

private static boolean allowFromConfig(Boolean configValue) {
return configValue != null ? configValue : ActivityInfrastructure.ALLOW_ACTIVITY_BY_DEFAULT;
}

private static Supplier<Map<Activity, ActivityConfiguration>> enumMapFactory() {
private static Supplier<Map<Activity, ActivityController>> enumMapFactory() {
return () -> new EnumMap<>(Activity.class);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import org.apache.commons.collections4.CollectionUtils;
import org.prebid.server.activity.infrastructure.creator.rule.RuleCreator;
import org.prebid.server.activity.infrastructure.rule.Rule;
import org.prebid.server.auction.gpp.model.GppContext;

import java.util.List;
import java.util.Map;
Expand All @@ -21,13 +20,13 @@ public ActivityRuleFactory(List<RuleCreator<?>> ruleCreators) {
Function.identity()));
}

public Rule from(Object ruleConfiguration, GppContext gppContext) {
public Rule from(Object ruleConfiguration, ActivityControllerCreationContext activityControllerCreationContext) {
final Class<?> ruleConfigurationClass = ruleConfiguration.getClass();
final RuleCreator<?> ruleCreator = ruleCreators.get(ruleConfigurationClass);
if (ruleCreator == null) {
throw new IllegalStateException("Rule creator for %s not found.".formatted(ruleConfigurationClass));
}

return ruleCreator.from(ruleConfiguration, gppContext);
return ruleCreator.from(ruleConfiguration, activityControllerCreationContext);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.prebid.server.activity.infrastructure.creator;

import lombok.Value;
import org.prebid.server.activity.Activity;
import org.prebid.server.auction.gpp.model.GppContext;
import org.prebid.server.settings.model.activity.privacy.AccountPrivacyModuleConfig;

@Value(staticConstructor = "of")
public class PrivacyModuleCreationContext {

Activity activity;

AccountPrivacyModuleConfig privacyModuleConfig;

GppContext gppContext;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.prebid.server.activity.infrastructure.creator.privacy;

import org.prebid.server.activity.infrastructure.creator.PrivacyModuleCreationContext;
import org.prebid.server.activity.infrastructure.privacy.PrivacyModule;
import org.prebid.server.activity.infrastructure.privacy.PrivacyModuleQualifier;

public interface PrivacyModuleCreator {

PrivacyModuleQualifier qualifier();

PrivacyModule from(PrivacyModuleCreationContext creationContext);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package org.prebid.server.activity.infrastructure.creator.privacy.usnat;

import com.iab.gpp.encoder.GppModel;
import org.prebid.server.activity.infrastructure.privacy.usnat.USNatGppReader;
import org.prebid.server.activity.infrastructure.privacy.usnat.reader.USCaliforniaGppReader;
import org.prebid.server.activity.infrastructure.privacy.usnat.reader.USColoradoGppReader;
import org.prebid.server.activity.infrastructure.privacy.usnat.reader.USConnecticutGppReader;
import org.prebid.server.activity.infrastructure.privacy.usnat.reader.USNationalGppReader;
import org.prebid.server.activity.infrastructure.privacy.usnat.reader.USUtahGppReader;
import org.prebid.server.activity.infrastructure.privacy.usnat.reader.USVirginiaGppReader;

public class USNatGppReaderFactory {

public USNatGppReader forSection(Integer sectionId, GppModel gppModel) {
return switch (USNatSection.from(sectionId)) {
case NATIONAL -> new USNationalGppReader(gppModel);
case CALIFORNIA -> new USCaliforniaGppReader(gppModel);
case VIRGINIA -> new USVirginiaGppReader(gppModel);
case COLORADO -> new USColoradoGppReader(gppModel);
case UTAH -> new USUtahGppReader(gppModel);
case CONNECTICUT -> new USConnecticutGppReader(gppModel);
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package org.prebid.server.activity.infrastructure.creator.privacy.usnat;

import com.iab.gpp.encoder.GppModel;
import org.apache.commons.collections4.SetUtils;
import org.prebid.server.activity.Activity;
import org.prebid.server.activity.infrastructure.creator.PrivacyModuleCreationContext;
import org.prebid.server.activity.infrastructure.creator.privacy.PrivacyModuleCreator;
import org.prebid.server.activity.infrastructure.privacy.PrivacyModule;
import org.prebid.server.activity.infrastructure.privacy.PrivacyModuleQualifier;
import org.prebid.server.activity.infrastructure.privacy.usnat.USNatModule;
import org.prebid.server.activity.infrastructure.rule.AndRule;
import org.prebid.server.auction.gpp.model.GppContext;
import org.prebid.server.settings.model.activity.privacy.AccountUSNatModuleConfig;

import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

public class USNatModuleCreator implements PrivacyModuleCreator {

private static final Set<Integer> ALLOWED_SECTIONS_IDS =
Arrays.stream(USNatSection.values())
.map(USNatSection::sectionId)
.collect(Collectors.toSet());

private final USNatGppReaderFactory gppReaderFactory;

public USNatModuleCreator(USNatGppReaderFactory gppReaderFactory) {
this.gppReaderFactory = Objects.requireNonNull(gppReaderFactory);
}

@Override
public PrivacyModuleQualifier qualifier() {
return PrivacyModuleQualifier.US_NAT;
}

@Override
public PrivacyModule from(PrivacyModuleCreationContext creationContext) {
final AccountUSNatModuleConfig moduleConfig = moduleConfig(creationContext);
final GppContext.Scope scope = creationContext.getGppContext().scope();

final List<PrivacyModule> innerPrivacyModules = SetUtils.emptyIfNull(scope.getSectionsIds()).stream()
.filter(sectionId -> !shouldSkip(sectionId, moduleConfig))
.map(sectionId -> forSection(creationContext.getActivity(), sectionId, scope.getGppModel()))
.toList();

final AndRule andRule = new AndRule(innerPrivacyModules);
return andRule::proceed;
}

private static AccountUSNatModuleConfig moduleConfig(PrivacyModuleCreationContext creationContext) {
return (AccountUSNatModuleConfig) creationContext.getPrivacyModuleConfig();
}

private static boolean shouldSkip(Integer sectionId, AccountUSNatModuleConfig moduleConfig) {
final AccountUSNatModuleConfig.Config config = moduleConfig.getConfig();
final List<Integer> skipSectionIds = config != null ? config.getSkipSids() : null;

return !ALLOWED_SECTIONS_IDS.contains(sectionId)
|| (skipSectionIds != null && skipSectionIds.contains(sectionId));
}

private PrivacyModule forSection(Activity activity, Integer sectionId, GppModel gppModel) {
return new USNatModule(activity, gppReaderFactory.forSection(sectionId, gppModel));
}
}
Loading

0 comments on commit 88f1fe1

Please sign in to comment.