From b236b53dc35ba21a38797548f4982c45628b02a2 Mon Sep 17 00:00:00 2001 From: Chris Eager Date: Fri, 11 Apr 2025 13:33:32 -0500 Subject: [PATCH] set profile: move updated badge calculation into account updater lambda --- .../controllers/DonationController.java | 29 ++++++++++--------- .../controllers/ProfileController.java | 9 +++--- .../grpc/ProfileGrpcService.java | 8 +++-- .../textsecuregcm/storage/AccountTest.java | 14 +++++++-- 4 files changed, 37 insertions(+), 23 deletions(-) diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/DonationController.java b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/DonationController.java index 6619094d8..daf3d4898 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/DonationController.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/DonationController.java @@ -97,21 +97,22 @@ public class DonationController { return redeemedReceiptsManager.put( receiptSerial, receiptExpiration.getEpochSecond(), receiptLevel, auth.getAccount().getUuid()) .thenCompose(receiptMatched -> { - if (!receiptMatched) { - return CompletableFuture.completedFuture( - Response.status(Status.BAD_REQUEST).entity("receipt serial is already redeemed") - .type(MediaType.TEXT_PLAIN_TYPE).build()); - } + if (!receiptMatched) { - return accountsManager.getByAccountIdentifierAsync(auth.getAccount().getUuid()) - .thenCompose(optionalAccount -> - optionalAccount.map(account -> accountsManager.updateAsync(account, a -> { - a.addBadge(clock, new AccountBadge(badgeId, receiptExpiration, request.isVisible())); - if (request.isPrimary()) { - a.makeBadgePrimaryIfExists(clock, badgeId); - } - })).orElse(CompletableFuture.completedFuture(null))) - .thenApply(ignored -> Response.ok().build()); + return CompletableFuture.completedFuture( + Response.status(Status.BAD_REQUEST).entity("receipt serial is already redeemed") + .type(MediaType.TEXT_PLAIN_TYPE).build()); + } + + return accountsManager.getByAccountIdentifierAsync(auth.getAccount().getUuid()) + .thenCompose(optionalAccount -> + optionalAccount.map(account -> accountsManager.updateAsync(account, a -> { + a.addBadge(clock, new AccountBadge(badgeId, receiptExpiration, request.isVisible())); + if (request.isPrimary()) { + a.makeBadgePrimaryIfExists(clock, badgeId); + } + })).orElse(CompletableFuture.completedFuture(null))) + .thenApply(ignored -> Response.ok().build()); }); }).thenCompose(Function.identity()); } 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 b4a88f645..f07f291b6 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/ProfileController.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/ProfileController.java @@ -204,11 +204,12 @@ public class ProfileController { .build())); } - final List updatedBadges = request.badges() - .map(badges -> ProfileHelper.mergeBadgeIdsWithExistingAccountBadges(clock, badgeConfigurationMap, badges, auth.getAccount().getBadges())) - .orElseGet(() -> auth.getAccount().getBadges()); - accountsManager.update(auth.getAccount(), a -> { + + final List updatedBadges = request.badges() + .map(badges -> ProfileHelper.mergeBadgeIdsWithExistingAccountBadges(clock, badgeConfigurationMap, badges, a.getBadges())) + .orElseGet(a::getBadges); + a.setBadges(clock, updatedBadges); a.setCurrentProfileVersion(request.version()); }); diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/grpc/ProfileGrpcService.java b/service/src/main/java/org/whispersystems/textsecuregcm/grpc/ProfileGrpcService.java index 6f27630f2..49462afeb 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/grpc/ProfileGrpcService.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/grpc/ProfileGrpcService.java @@ -145,11 +145,13 @@ public class ProfileGrpcService extends ReactorProfileGrpc.ProfileImplBase { request.getCommitment().toByteArray()))); final List> updates = new ArrayList<>(2); - final List updatedBadges = Optional.of(request.getBadgeIdsList()) - .map(badges -> ProfileHelper.mergeBadgeIdsWithExistingAccountBadges(clock, badgeConfigurationMap, badges, account.getBadges())) - .orElseGet(account::getBadges); updates.add(Mono.fromFuture(() -> accountsManager.updateAsync(account, a -> { + + final List updatedBadges = Optional.of(request.getBadgeIdsList()) + .map(badges -> ProfileHelper.mergeBadgeIdsWithExistingAccountBadges(clock, badgeConfigurationMap, badges, a.getBadges())) + .orElseGet(a::getBadges); + a.setBadges(clock, updatedBadges); a.setCurrentProfileVersion(request.getVersion()); }))); diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/storage/AccountTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/storage/AccountTest.java index 29f9c47f1..af46b0ada 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/storage/AccountTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/storage/AccountTest.java @@ -19,7 +19,6 @@ import static org.whispersystems.textsecuregcm.tests.util.DevicesHelper.createDe import com.fasterxml.jackson.annotation.JsonFilter; import java.lang.annotation.Annotation; import java.nio.charset.StandardCharsets; -import java.time.Clock; import java.time.Instant; import java.util.Arrays; import java.util.Collections; @@ -187,7 +186,7 @@ class AccountTest { @Test void addAndRemoveBadges() { final Account account = AccountsHelper.generateTestAccount("+14151234567", UUID.randomUUID(), UUID.randomUUID(), List.of(createDevice(Device.PRIMARY_ID)), new byte[0]); - final Clock clock = TestClock.pinned(Instant.ofEpochSecond(40)); + final TestClock clock = TestClock.pinned(Instant.ofEpochSecond(40)); account.addBadge(clock, new AccountBadge("foo", Instant.ofEpochSecond(42), false)); account.addBadge(clock, new AccountBadge("bar", Instant.ofEpochSecond(44), true)); @@ -214,6 +213,17 @@ class AccountTest { assertThat(badge.expiration().getEpochSecond()).isEqualTo(51); assertThat(badge.visible()).isTrue(); }); + + clock.pin(Instant.ofEpochSecond(52)); + + // for a merged badge, visible = true is preferred + account.addBadge(clock, new AccountBadge("foo", Instant.ofEpochSecond(53), false)); + + assertThat(account.getBadges()).hasSize(1).element(0).satisfies(badge -> { + assertThat(badge.id()).isEqualTo("foo"); + assertThat(badge.expiration().getEpochSecond()).isEqualTo(53); + assertThat(badge.visible()).isTrue(); + }); } @Test