From bd5f5c407b095e056bd42d1aa65772be7ab70616 Mon Sep 17 00:00:00 2001 From: Ehren Kret Date: Fri, 17 Sep 2021 11:15:45 -0500 Subject: [PATCH] Add method to merge badge ids list into a profile --- .../controllers/ProfileController.java | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/ProfileController.java b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/ProfileController.java index f9657fb7b..d9a49c681 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/ProfileController.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/ProfileController.java @@ -8,13 +8,21 @@ package org.whispersystems.textsecuregcm.controllers; import com.codahale.metrics.annotation.Timed; import io.dropwizard.auth.Auth; import java.security.SecureRandom; +import java.time.Clock; +import java.time.Duration; import java.time.ZoneOffset; import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; +import java.util.Map; +import java.util.Map.Entry; import java.util.Optional; import java.util.Set; import java.util.UUID; +import java.util.function.Function; +import java.util.stream.Collectors; import javax.validation.Valid; import javax.validation.valueextraction.Unwrapping; import javax.ws.rs.Consumes; @@ -49,6 +57,8 @@ import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount; import org.whispersystems.textsecuregcm.auth.OptionalAccess; import org.whispersystems.textsecuregcm.auth.UnidentifiedAccessChecksum; import org.whispersystems.textsecuregcm.badges.ProfileBadgeConverter; +import org.whispersystems.textsecuregcm.configuration.BadgeConfiguration; +import org.whispersystems.textsecuregcm.configuration.BadgesConfiguration; import org.whispersystems.textsecuregcm.entities.CreateProfileRequest; import org.whispersystems.textsecuregcm.entities.Profile; import org.whispersystems.textsecuregcm.entities.ProfileAvatarUploadAttributes; @@ -57,6 +67,7 @@ import org.whispersystems.textsecuregcm.limits.RateLimiters; import org.whispersystems.textsecuregcm.s3.PolicySigner; import org.whispersystems.textsecuregcm.s3.PostPolicyGenerator; import org.whispersystems.textsecuregcm.storage.Account; +import org.whispersystems.textsecuregcm.storage.AccountBadge; import org.whispersystems.textsecuregcm.storage.AccountsManager; import org.whispersystems.textsecuregcm.storage.DynamicConfigurationManager; import org.whispersystems.textsecuregcm.storage.ProfilesManager; @@ -74,12 +85,14 @@ public class ProfileController { private final Logger logger = LoggerFactory.getLogger(ProfileController.class); + private final Clock clock; private final RateLimiters rateLimiters; private final ProfilesManager profilesManager; private final AccountsManager accountsManager; private final UsernamesManager usernamesManager; private final DynamicConfigurationManager dynamicConfigurationManager; private final ProfileBadgeConverter profileBadgeConverter; + private final Map badgeConfigurationMap; private final PolicySigner policySigner; private final PostPolicyGenerator policyGenerator; @@ -90,24 +103,29 @@ public class ProfileController { private final String bucket; public ProfileController( + Clock clock, RateLimiters rateLimiters, AccountsManager accountsManager, ProfilesManager profilesManager, UsernamesManager usernamesManager, DynamicConfigurationManager dynamicConfigurationManager, ProfileBadgeConverter profileBadgeConverter, + BadgesConfiguration badgesConfiguration, S3Client s3client, PostPolicyGenerator policyGenerator, PolicySigner policySigner, String bucket, ServerZkProfileOperations zkProfileOperations, boolean isZkEnabled) { + this.clock = clock; this.rateLimiters = rateLimiters; this.accountsManager = accountsManager; this.profilesManager = profilesManager; this.usernamesManager = usernamesManager; this.dynamicConfigurationManager = dynamicConfigurationManager; this.profileBadgeConverter = profileBadgeConverter; + this.badgeConfigurationMap = badgesConfiguration.getBadges().stream().collect(Collectors.toMap( + BadgeConfiguration::getId, Function.identity())); this.zkProfileOperations = zkProfileOperations; this.bucket = bucket; this.s3client = s3client; @@ -447,4 +465,52 @@ public class ProfileController { return List.of(); } } + + private List mergeBadgeIdsWithExistingAccountBadges( + final List badgeIds, + final List accountBadges) { + LinkedHashMap existingBadges = new LinkedHashMap<>(accountBadges.size()); + for (final AccountBadge accountBadge : accountBadges) { + existingBadges.putIfAbsent(accountBadge.getId(), accountBadge); + } + + LinkedHashMap result = new LinkedHashMap<>(accountBadges.size()); + for (final String badgeId : badgeIds) { + + // duplicate in the list, ignore it + if (result.containsKey(badgeId)) { + continue; + } + + // reordering or making visible existing badges + if (existingBadges.containsKey(badgeId)) { + AccountBadge accountBadge = existingBadges.get(badgeId); + if (!accountBadge.isVisible()) { + accountBadge = new AccountBadge(badgeId, accountBadge.getExpiration(), true); + } + result.put(badgeId, accountBadge); + continue; + } + + // This is for testing badges and allows them to be added to an account at any time with an expiration of 1 day + // in the future. + BadgeConfiguration badgeConfiguration = badgeConfigurationMap.get(badgeId); + if (badgeConfiguration != null && "testing".equals(badgeConfiguration.getCategory())) { + result.put(badgeId, new AccountBadge(badgeId, clock.instant().plus(Duration.ofDays(1)), true)); + } + } + + // take any remaining account badges and make them invisible + for (final Entry entry : existingBadges.entrySet()) { + if (!result.containsKey(entry.getKey())) { + AccountBadge accountBadge = entry.getValue(); + if (accountBadge.isVisible()) { + accountBadge = new AccountBadge(accountBadge.getId(), accountBadge.getExpiration(), false); + } + result.put(accountBadge.getId(), accountBadge); + } + } + + return new ArrayList<>(result.values()); + } }