Skip to content

Commit

Permalink
Added basicEnforcementVendors fro TCF (#1236)
Browse files Browse the repository at this point in the history
  • Loading branch information
DGarbar authored May 5, 2021
1 parent a3eff0d commit ded8eba
Show file tree
Hide file tree
Showing 40 changed files with 580 additions and 416 deletions.
13 changes: 7 additions & 6 deletions src/main/java/org/prebid/server/privacy/gdpr/GdprService.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import org.prebid.server.privacy.gdpr.model.PrivacyEnforcementAction;
import org.prebid.server.privacy.gdpr.model.VendorPermission;
import org.prebid.server.privacy.gdpr.vendorlist.VendorListService;
import org.prebid.server.privacy.gdpr.vendorlist.proto.Purpose;
import org.prebid.server.privacy.gdpr.vendorlist.proto.PurposeCode;
import org.prebid.server.privacy.gdpr.vendorlist.proto.VendorListV1;
import org.prebid.server.privacy.gdpr.vendorlist.proto.VendorV1;

Expand Down Expand Up @@ -120,7 +120,7 @@ private static VendorPermission toVendorPermission(Integer vendorId,
final VendorV1 vendorListEntry = vendorListMapping.get(vendorId);

// confirm purposes
final EnumSet<Purpose> claimedPurposes = vendorListEntry.combinedPurposes();
final EnumSet<PurposeCode> claimedPurposes = vendorListEntry.combinedPurposes();
final boolean claimedPurposesAllowed = isClaimedPurposesAllowed(claimedPurposes, allowedPurposeIds);
final boolean purposeOneClaimedAndAllowed = isPurposeOneClaimedAndAllowed(claimedPurposes, allowedPurposeIds);

Expand All @@ -144,14 +144,15 @@ private static boolean isVendorAllowed(VendorConsent vendorConsent, Integer vend
}
}

private static boolean isClaimedPurposesAllowed(EnumSet<Purpose> claimedPurposes, Set<Integer> allowedPurposeIds) {
return claimedPurposes.stream().allMatch(o -> allowedPurposeIds.contains(o.code()));
private static boolean isClaimedPurposesAllowed(EnumSet<PurposeCode> claimedPurposeCodes,
Set<Integer> allowedPurposeIds) {
return claimedPurposeCodes.stream().allMatch(o -> allowedPurposeIds.contains(o.code()));
}

private static boolean isPurposeOneClaimedAndAllowed(
EnumSet<Purpose> claimedPurposes, Set<Integer> allowedPurposeIds) {
EnumSet<PurposeCode> claimedPurposeCodes, Set<Integer> allowedPurposeIds) {

return claimedPurposes.contains(Purpose.ONE) && allowedPurposeIds.contains(Purpose.ONE.code());
return claimedPurposeCodes.contains(PurposeCode.ONE) && allowedPurposeIds.contains(PurposeCode.ONE.code());
}

private static PrivacyEnforcementAction allDenied() {
Expand Down
127 changes: 99 additions & 28 deletions src/main/java/org/prebid/server/privacy/gdpr/Tcf2Service.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@

import com.iabtcf.decoder.TCString;
import io.vertx.core.Future;
import lombok.Value;
import org.apache.commons.collections4.CollectionUtils;
import org.prebid.server.bidder.BidderCatalog;
import org.prebid.server.privacy.gdpr.model.PrivacyEnforcementAction;
import org.prebid.server.privacy.gdpr.model.VendorPermission;
import org.prebid.server.privacy.gdpr.model.VendorPermissionWithGvl;
import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.PurposeStrategy;
import org.prebid.server.privacy.gdpr.tcfstrategies.specialfeature.SpecialFeaturesStrategy;
import org.prebid.server.privacy.gdpr.vendorlist.VendorListServiceV2;
import org.prebid.server.privacy.gdpr.vendorlist.proto.PurposeCode;
import org.prebid.server.privacy.gdpr.vendorlist.proto.VendorV2;
import org.prebid.server.settings.model.AccountGdprConfig;
import org.prebid.server.settings.model.EnforcePurpose;
Expand All @@ -20,11 +23,13 @@
import org.prebid.server.settings.model.SpecialFeatures;

import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Tcf2Service {

Expand Down Expand Up @@ -92,25 +97,59 @@ private Future<Collection<VendorPermission>> permissionsForInternal(Collection<V
final PurposeOneTreatmentInterpretation mergedPurposeOneTreatmentInterpretation =
mergePurposeOneTreatmentInterpretation(accountGdprConfig);

final VendorPermissionsByType<VendorPermission> vendorPermissionsByType = toVendorPermissionsByType(
vendorPermissions, accountGdprConfig);

return vendorListServiceV2.forVersion(tcfConsent.getVendorListVersion())
.map(vendorGvlPermissions -> wrapWithGVL(vendorPermissions, vendorGvlPermissions))
.map(vendorGvlPermissions -> wrapWithGVL(vendorPermissionsByType, vendorGvlPermissions))

.compose(gvlResult -> processSupportedPurposeStrategies(tcfConsent, gvlResult, mergedPurposes,
purposeOneTreatmentInterpretation),
ignoredFailed -> processDowngradedSupportedPurposeStrategies(tcfConsent, vendorPermissions,
mergedPurposes, mergedPurposeOneTreatmentInterpretation))
ignoredFailed -> processDowngradedSupportedPurposeStrategies(tcfConsent,
vendorPermissionsByType, mergedPurposes, mergedPurposeOneTreatmentInterpretation))

.map(changedVendorPermissions -> processSupportedSpecialFeatureStrategies(tcfConsent,
changedVendorPermissions, mergedSpecialFeatures));
}

private static VendorPermissionsByType<VendorPermission> toVendorPermissionsByType(
Collection<VendorPermission> vendorPermissions,
AccountGdprConfig accountGdprConfig) {

final List<String> basicEnforcedVendors = accountGdprConfig != null
? accountGdprConfig.getBasicEnforcementVendors()
: null;
if (CollectionUtils.isEmpty(basicEnforcedVendors)) {
return VendorPermissionsByType.of(Collections.emptyList(), vendorPermissions);
}

final Map<Boolean, List<VendorPermission>> isBasicEnforcedToPermissions = vendorPermissions.stream()
.collect(Collectors.partitioningBy(vendorPermission ->
basicEnforcedVendors.contains(vendorPermission.getBidderName())));

final List<VendorPermission> weakPermissions = isBasicEnforcedToPermissions.getOrDefault(true,
Collections.emptyList());

final List<VendorPermission> standardPermissions = isBasicEnforcedToPermissions.getOrDefault(false,
Collections.emptyList());

return VendorPermissionsByType.of(weakPermissions, standardPermissions);
}

private static Collection<VendorPermissionWithGvl> wrapWithGVL(Collection<VendorPermission> vendorPermissions,
Map<Integer, VendorV2> vendorGvlPermissions) {
private static VendorPermissionsByType<VendorPermissionWithGvl> wrapWithGVL(
VendorPermissionsByType<VendorPermission> vendorPermissionsByType,
Map<Integer, VendorV2> vendorGvlPermissions) {

return vendorPermissions.stream()
final List<VendorPermissionWithGvl> weakPermissions = vendorPermissionsByType.getWeakPermissions().stream()
.map(vendorPermission -> wrapWithGVL(vendorPermission, vendorGvlPermissions))
.collect(Collectors.toList());

final List<VendorPermissionWithGvl> standardPermissions = vendorPermissionsByType.getStandardPermissions()
.stream()
.map(vendorPermission -> wrapWithGVL(vendorPermission, vendorGvlPermissions))
.collect(Collectors.toList());

return VendorPermissionsByType.of(weakPermissions, standardPermissions);
}

private static VendorPermissionWithGvl wrapWithGVL(VendorPermission vendorPermission,
Expand All @@ -126,38 +165,57 @@ private static VendorPermissionWithGvl wrapWithGVL(VendorPermission vendorPermis

private Future<Collection<VendorPermission>> processSupportedPurposeStrategies(
TCString tcfConsent,
Collection<VendorPermissionWithGvl> vendorPermissionsWithGvl,
VendorPermissionsByType<VendorPermissionWithGvl> vendorPermissionsByType,
Purposes purposes,
PurposeOneTreatmentInterpretation purposeOneTreatmentInterpretation) {

for (PurposeStrategy purposeStrategy : purposeStrategies) {
final org.prebid.server.privacy.gdpr.vendorlist.proto.Purpose tcfPurpose = purposeStrategy.getPurpose();
final PurposeCode tcfPurpose = purposeStrategy.getPurpose();
final Purpose purposeById = findPurposeByTcfPurpose(tcfPurpose, purposes);
processPurposeStrategy(tcfConsent, vendorPermissionsWithGvl, purposeById, purposeStrategy,
final Purpose weakPurpose = weakPurpose(purposeById);

final Collection<VendorPermissionWithGvl> standardPermissions = vendorPermissionsByType
.getStandardPermissions();
final Collection<VendorPermissionWithGvl> weakPermissions = vendorPermissionsByType.getWeakPermissions();

processPurposeStrategy(tcfConsent, standardPermissions, purposeById, purposeStrategy,
purposeOneTreatmentInterpretation, false);
processPurposeStrategy(tcfConsent, weakPermissions, weakPurpose, purposeStrategy,
purposeOneTreatmentInterpretation, true);
}

return Future.succeededFuture(vendorPermissionsWithGvl.stream()
return Future.succeededFuture(vendorPermissionsByType.joinPermissions().stream()
.map(VendorPermissionWithGvl::getVendorPermission)
.collect(Collectors.toList()));
}

private Future<Collection<VendorPermission>> processDowngradedSupportedPurposeStrategies(
TCString tcfConsent,
Collection<VendorPermission> vendorPermissions,
VendorPermissionsByType<VendorPermission> vendorPermissionsByType,
Purposes purposes,
PurposeOneTreatmentInterpretation purposeOneTreatmentInterpretation) {

final List<VendorPermissionWithGvl> vendorPermissionsWithGvl = wrapWithEmptyGVL(vendorPermissions);
final VendorPermissionsByType<VendorPermissionWithGvl> vendorPermissionsWithGvlByType = wrapWithGVL(
vendorPermissionsByType, Collections.emptyMap());

for (PurposeStrategy purposeStrategy : purposeStrategies) {
final org.prebid.server.privacy.gdpr.vendorlist.proto.Purpose tcfPurpose = purposeStrategy.getPurpose();
final Purpose downgradedPurpose = downgradePurpose(findPurposeByTcfPurpose(tcfPurpose, purposes));
processPurposeStrategy(tcfConsent, vendorPermissionsWithGvl, downgradedPurpose, purposeStrategy,
final PurposeCode tcfPurpose = purposeStrategy.getPurpose();
final Purpose downgradedPurposeById = downgradePurpose(findPurposeByTcfPurpose(tcfPurpose, purposes));
final Purpose weakPurpose = weakPurpose(downgradedPurposeById);

final Collection<VendorPermissionWithGvl> standardPermissions = vendorPermissionsWithGvlByType
.getStandardPermissions();
final Collection<VendorPermissionWithGvl> weakPermissions = vendorPermissionsWithGvlByType
.getWeakPermissions();

processPurposeStrategy(tcfConsent, standardPermissions, downgradedPurposeById, purposeStrategy,
purposeOneTreatmentInterpretation, true);
processPurposeStrategy(tcfConsent, weakPermissions, weakPurpose, purposeStrategy,
purposeOneTreatmentInterpretation, true);

}

return Future.succeededFuture(vendorPermissions);
return Future.succeededFuture(vendorPermissionsByType.joinPermissions());
}

private void processPurposeStrategy(TCString tcfConsent,
Expand All @@ -167,7 +225,7 @@ private void processPurposeStrategy(TCString tcfConsent,
PurposeOneTreatmentInterpretation purposeOneTreatmentInterpretation,
boolean wasDowngraded) {

if (purposeStrategy.getPurpose() == org.prebid.server.privacy.gdpr.vendorlist.proto.Purpose.ONE
if (purposeStrategy.getPurpose() == PurposeCode.ONE
&& tcfConsent.getPurposeOneTreatment()) {

processPurposeOneTreatment(
Expand Down Expand Up @@ -204,13 +262,6 @@ private void processPurposeOneTreatment(PurposeOneTreatmentInterpretation purpos
}
}

private static List<VendorPermissionWithGvl> wrapWithEmptyGVL(Collection<VendorPermission> vendorPermissions) {
return vendorPermissions.stream()
.map(vendorPermission -> VendorPermissionWithGvl.of(vendorPermission,
VendorV2.empty(vendorPermission.getVendorId())))
.collect(Collectors.toList());
}

private static Purpose downgradePurpose(Purpose purpose) {
final EnforcePurpose enforcePurpose = purpose.getEnforcePurpose();

Expand All @@ -219,6 +270,16 @@ private static Purpose downgradePurpose(Purpose purpose) {
: purpose;
}

private static Purpose weakPurpose(Purpose purpose) {
final EnforcePurpose enforcePurpose = purpose.getEnforcePurpose();
final EnforcePurpose downgradedEnforce =
enforcePurpose == null || Objects.equals(enforcePurpose, EnforcePurpose.full)
? EnforcePurpose.basic
: enforcePurpose;

return Purpose.of(downgradedEnforce, false, purpose.getVendorExceptions());
}

private Collection<VendorPermission> processSupportedSpecialFeatureStrategies(
TCString tcfConsent,
Collection<VendorPermission> vendorPermissions,
Expand Down Expand Up @@ -265,10 +326,7 @@ private SpecialFeatures mergeAccountSpecialFeatures(AccountGdprConfig accountGdp
.build();
}

private Purpose findPurposeByTcfPurpose(
org.prebid.server.privacy.gdpr.vendorlist.proto.Purpose tcfPurpose,
Purposes purposes) {

private Purpose findPurposeByTcfPurpose(PurposeCode tcfPurpose, Purposes purposes) {
switch (tcfPurpose) {
case ONE:
return purposes.getP1();
Expand Down Expand Up @@ -320,4 +378,17 @@ private PurposeOneTreatmentInterpretation mergePurposeOneTreatmentInterpretation
private static <T> T mergeItem(T prioritisedItem, T item) {
return prioritisedItem == null ? item : prioritisedItem;
}

@Value(staticConstructor = "of")
private static class VendorPermissionsByType<T> {

Collection<T> weakPermissions;

Collection<T> standardPermissions;

public Collection<T> joinPermissions() {
return Stream.concat(weakPermissions.stream(), standardPermissions.stream())
.collect(Collectors.toList());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.BasicEnforcePurposeStrategy;
import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.FullEnforcePurposeStrategy;
import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.NoEnforcePurposeStrategy;
import org.prebid.server.privacy.gdpr.vendorlist.proto.Purpose;
import org.prebid.server.privacy.gdpr.vendorlist.proto.PurposeCode;

public class PurposeEightStrategy extends PurposeStrategy {

Expand All @@ -26,8 +26,8 @@ public void allowNaturally(PrivacyEnforcementAction privacyEnforcementAction) {
}

@Override
public Purpose getPurpose() {
return Purpose.EIGHT;
public PurposeCode getPurpose() {
return PurposeCode.EIGHT;
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.BasicEnforcePurposeStrategy;
import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.FullEnforcePurposeStrategy;
import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.NoEnforcePurposeStrategy;
import org.prebid.server.privacy.gdpr.vendorlist.proto.Purpose;
import org.prebid.server.privacy.gdpr.vendorlist.proto.PurposeCode;

public class PurposeFiveStrategy extends PurposeStrategy {

Expand All @@ -26,8 +26,8 @@ public void allowNaturally(PrivacyEnforcementAction privacyEnforcementAction) {
}

@Override
public Purpose getPurpose() {
return Purpose.FIVE;
public PurposeCode getPurpose() {
return PurposeCode.FIVE;
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.BasicEnforcePurposeStrategy;
import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.FullEnforcePurposeStrategy;
import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.NoEnforcePurposeStrategy;
import org.prebid.server.privacy.gdpr.vendorlist.proto.Purpose;
import org.prebid.server.privacy.gdpr.vendorlist.proto.PurposeCode;

public class PurposeFourStrategy extends PurposeStrategy {

Expand All @@ -26,8 +26,8 @@ public void allowNaturally(PrivacyEnforcementAction privacyEnforcementAction) {
}

@Override
public Purpose getPurpose() {
return Purpose.FOUR;
public PurposeCode getPurpose() {
return PurposeCode.FOUR;
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.BasicEnforcePurposeStrategy;
import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.FullEnforcePurposeStrategy;
import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.NoEnforcePurposeStrategy;
import org.prebid.server.privacy.gdpr.vendorlist.proto.Purpose;
import org.prebid.server.privacy.gdpr.vendorlist.proto.PurposeCode;

public class PurposeNineStrategy extends PurposeStrategy {

Expand All @@ -26,8 +26,8 @@ public void allowNaturally(PrivacyEnforcementAction privacyEnforcementAction) {
}

@Override
public Purpose getPurpose() {
return Purpose.NINE;
public PurposeCode getPurpose() {
return PurposeCode.NINE;
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.BasicEnforcePurposeStrategy;
import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.FullEnforcePurposeStrategy;
import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.NoEnforcePurposeStrategy;
import org.prebid.server.privacy.gdpr.vendorlist.proto.Purpose;
import org.prebid.server.privacy.gdpr.vendorlist.proto.PurposeCode;

public class PurposeOneStrategy extends PurposeStrategy {

Expand All @@ -25,8 +25,8 @@ public void allowNaturally(PrivacyEnforcementAction privacyEnforcementAction) {
}

@Override
public Purpose getPurpose() {
return Purpose.ONE;
public PurposeCode getPurpose() {
return PurposeCode.ONE;
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.BasicEnforcePurposeStrategy;
import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.FullEnforcePurposeStrategy;
import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.NoEnforcePurposeStrategy;
import org.prebid.server.privacy.gdpr.vendorlist.proto.Purpose;
import org.prebid.server.privacy.gdpr.vendorlist.proto.PurposeCode;

public class PurposeSevenStrategy extends PurposeStrategy {

Expand All @@ -27,8 +27,8 @@ public void allowNaturally(PrivacyEnforcementAction privacyEnforcementAction) {
}

@Override
public Purpose getPurpose() {
return Purpose.SEVEN;
public PurposeCode getPurpose() {
return PurposeCode.SEVEN;
}

}
Expand Down
Loading

0 comments on commit ded8eba

Please sign in to comment.