From e1aa734c40ee77feb83f36a50462424cbb449a6d Mon Sep 17 00:00:00 2001 From: Katherine Date: Thu, 5 Oct 2023 09:53:33 -0700 Subject: [PATCH] Define endpoint to get localized bank mandate text --- .../textsecuregcm/WhisperServerService.java | 4 ++- .../controllers/SubscriptionController.java | 21 ++++++++++- .../subscriptions/BankMandateTranslator.java | 35 +++++++++++++++++++ .../subscriptions/BankTransferType.java | 10 ++++++ .../signal/bankmandate/BankMandate.properties | 7 ++++ .../SubscriptionControllerTest.java | 23 +++++++++++- 6 files changed, 97 insertions(+), 3 deletions(-) create mode 100644 service/src/main/java/org/whispersystems/textsecuregcm/subscriptions/BankMandateTranslator.java create mode 100644 service/src/main/java/org/whispersystems/textsecuregcm/subscriptions/BankTransferType.java create mode 100644 service/src/main/resources/org/signal/bankmandate/BankMandate.properties diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java b/service/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java index 1f9388fe9..50a701e76 100644 --- a/service/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java +++ b/service/src/main/java/org/whispersystems/textsecuregcm/WhisperServerService.java @@ -199,6 +199,7 @@ import org.whispersystems.textsecuregcm.storage.ReportMessageManager; import org.whispersystems.textsecuregcm.storage.SubscriptionManager; import org.whispersystems.textsecuregcm.storage.VerificationSessionManager; import org.whispersystems.textsecuregcm.storage.VerificationSessions; +import org.whispersystems.textsecuregcm.subscriptions.BankMandateTranslator; import org.whispersystems.textsecuregcm.subscriptions.BraintreeManager; import org.whispersystems.textsecuregcm.subscriptions.StripeManager; import org.whispersystems.textsecuregcm.util.DynamoDbFromConfig; @@ -294,6 +295,7 @@ public class WhisperServerService extends Application buildCurrencyConfiguration(@Nullable final UserAgent userAgent) { @@ -587,6 +592,20 @@ public class SubscriptionController { }); } + @GET + @Path("/bank_mandate/{bankTransferType}") + @Produces(MediaType.APPLICATION_JSON) + public CompletableFuture getBankMandate(final @Context ContainerRequestContext containerRequestContext, + final @PathParam("bankTransferType") BankTransferType bankTransferType) { + return CompletableFuture.supplyAsync(() -> { + List acceptableLanguages = getAcceptableLanguagesForRequest(containerRequestContext); + return Response.ok(new GetBankMandateResponse( + bankMandateTranslator.translate(acceptableLanguages, bankTransferType))).build(); + }); + } + + public record GetBankMandateResponse(String mandate) {} + public record GetBoostBadgesResponse(Map levels) { public record Level(PurchasableBadge badge) { } diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/subscriptions/BankMandateTranslator.java b/service/src/main/java/org/whispersystems/textsecuregcm/subscriptions/BankMandateTranslator.java new file mode 100644 index 000000000..438617b1a --- /dev/null +++ b/service/src/main/java/org/whispersystems/textsecuregcm/subscriptions/BankMandateTranslator.java @@ -0,0 +1,35 @@ +/* + * Copyright 2023 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.whispersystems.textsecuregcm.subscriptions; + +import java.util.List; +import java.util.Locale; +import java.util.Objects; +import java.util.ResourceBundle; +import javax.annotation.Nonnull; +import org.signal.i18n.HeaderControlledResourceBundleLookup; + +public class BankMandateTranslator { + private static final String BASE_NAME = "org.signal.bankmandate.BankMandate"; + private final HeaderControlledResourceBundleLookup headerControlledResourceBundleLookup; + + public BankMandateTranslator( + @Nonnull final HeaderControlledResourceBundleLookup headerControlledResourceBundleLookup) { + this.headerControlledResourceBundleLookup = Objects.requireNonNull(headerControlledResourceBundleLookup); + } + + public String translate(final List acceptableLanguages, final BankTransferType bankTransferType) { + final ResourceBundle resourceBundle = headerControlledResourceBundleLookup.getResourceBundle(BASE_NAME, + acceptableLanguages); + return resourceBundle.getString(getKey(bankTransferType)); + } + + private static String getKey(final BankTransferType bankTransferType) { + return switch (bankTransferType) { + case SEPA_DEBIT -> "SEPA_MANDATE"; + }; + } +} diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/subscriptions/BankTransferType.java b/service/src/main/java/org/whispersystems/textsecuregcm/subscriptions/BankTransferType.java new file mode 100644 index 000000000..589202692 --- /dev/null +++ b/service/src/main/java/org/whispersystems/textsecuregcm/subscriptions/BankTransferType.java @@ -0,0 +1,10 @@ +/* + * Copyright 2023 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.whispersystems.textsecuregcm.subscriptions; + +public enum BankTransferType { + SEPA_DEBIT +} diff --git a/service/src/main/resources/org/signal/bankmandate/BankMandate.properties b/service/src/main/resources/org/signal/bankmandate/BankMandate.properties new file mode 100644 index 000000000..e9492beda --- /dev/null +++ b/service/src/main/resources/org/signal/bankmandate/BankMandate.properties @@ -0,0 +1,7 @@ +# +# Copyright 2023 Signal Messenger, LLC +# SPDX-License-Identifier: AGPL-3.0-only +# + +SEPA_MANDATE = By providing your payment information and confirming this payment, you authorise (A) Signal Technology Foundation and Stripe, our payment service provider, to send instructions to your bank to debit your account and (B) your bank to debit your account in accordance with those instructions. As part of your rights, you are entitled to a refund from your bank under the terms and conditions of your agreement with your bank. A refund must be claimed within 8 weeks starting from the date on which your account was debited. Your rights are explained in a statement that you can obtain from your bank. You agree to receive notifications for future debits up to 2 days before they occur. + diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/controllers/SubscriptionControllerTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/controllers/SubscriptionControllerTest.java index 1594de87e..98f61156b 100644 --- a/service/src/test/java/org/whispersystems/textsecuregcm/controllers/SubscriptionControllerTest.java +++ b/service/src/test/java/org/whispersystems/textsecuregcm/controllers/SubscriptionControllerTest.java @@ -60,6 +60,7 @@ import org.whispersystems.textsecuregcm.badges.BadgeTranslator; import org.whispersystems.textsecuregcm.badges.LevelTranslator; import org.whispersystems.textsecuregcm.configuration.OneTimeDonationConfiguration; import org.whispersystems.textsecuregcm.configuration.SubscriptionConfiguration; +import org.whispersystems.textsecuregcm.controllers.SubscriptionController.GetBankMandateResponse; import org.whispersystems.textsecuregcm.controllers.SubscriptionController.GetSubscriptionConfigurationResponse; import org.whispersystems.textsecuregcm.entities.Badge; import org.whispersystems.textsecuregcm.entities.BadgeSvg; @@ -67,6 +68,7 @@ import org.whispersystems.textsecuregcm.mappers.CompletionExceptionMapper; import org.whispersystems.textsecuregcm.mappers.SubscriptionProcessorExceptionMapper; import org.whispersystems.textsecuregcm.storage.IssuedReceiptsManager; import org.whispersystems.textsecuregcm.storage.SubscriptionManager; +import org.whispersystems.textsecuregcm.subscriptions.BankMandateTranslator; import org.whispersystems.textsecuregcm.subscriptions.BraintreeManager; import org.whispersystems.textsecuregcm.subscriptions.BraintreeManager.PayPalOneTimePaymentApprovalDetails; import org.whispersystems.textsecuregcm.subscriptions.ChargeFailure; @@ -97,9 +99,10 @@ class SubscriptionControllerTest { private static final IssuedReceiptsManager ISSUED_RECEIPTS_MANAGER = mock(IssuedReceiptsManager.class); private static final BadgeTranslator BADGE_TRANSLATOR = mock(BadgeTranslator.class); private static final LevelTranslator LEVEL_TRANSLATOR = mock(LevelTranslator.class); + private static final BankMandateTranslator BANK_MANDATE_TRANSLATOR = mock(BankMandateTranslator.class); private static final SubscriptionController SUBSCRIPTION_CONTROLLER = new SubscriptionController( CLOCK, SUBSCRIPTION_CONFIG, ONETIME_CONFIG, SUBSCRIPTION_MANAGER, STRIPE_MANAGER, BRAINTREE_MANAGER, ZK_OPS, - ISSUED_RECEIPTS_MANAGER, BADGE_TRANSLATOR, LEVEL_TRANSLATOR); + ISSUED_RECEIPTS_MANAGER, BADGE_TRANSLATOR, LEVEL_TRANSLATOR, BANK_MANDATE_TRANSLATOR); private static final ResourceExtension RESOURCE_EXTENSION = ResourceExtension.builder() .addProperty(ServerProperties.UNWRAP_COMPLETION_STAGE_IN_WRITER_ENABLE, Boolean.TRUE) .addProvider(AuthHelper.getAuthFilter()) @@ -710,6 +713,24 @@ class SubscriptionControllerTest { ); } + @Test + void testGetBankMandate() { + when(BANK_MANDATE_TRANSLATOR.translate(any(), any())).thenReturn("bankMandate"); + final Response response = RESOURCE_EXTENSION.target("/v1/subscription/bank_mandate/sepa_debit") + .request() + .get(); + assertThat(response.getStatus()).isEqualTo(200); + assertThat(response.readEntity(GetBankMandateResponse.class).mandate()).isEqualTo("bankMandate"); + } + + @Test + void testGetBankMandateInvalidBankTransferType() { + final Response response = RESOURCE_EXTENSION.target("/v1/subscription/ach") + .request() + .get(); + assertThat(response.getStatus()).isEqualTo(404); + } + @ParameterizedTest @MethodSource void getSubscriptionConfiguration(final String userAgent, final boolean expectSepa) {