Remove iOS special case handling logic for SEPA/iDEAL
This commit is contained in:
parent
f082b95efb
commit
498ace0488
|
@ -35,7 +35,6 @@ import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.CompletionException;
|
import java.util.concurrent.CompletionException;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import javax.crypto.Mac;
|
import javax.crypto.Mac;
|
||||||
import javax.crypto.spec.SecretKeySpec;
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
import javax.validation.Valid;
|
import javax.validation.Valid;
|
||||||
|
@ -99,10 +98,6 @@ import org.whispersystems.textsecuregcm.subscriptions.SubscriptionCurrencyUtil;
|
||||||
import org.whispersystems.textsecuregcm.subscriptions.SubscriptionProcessor;
|
import org.whispersystems.textsecuregcm.subscriptions.SubscriptionProcessor;
|
||||||
import org.whispersystems.textsecuregcm.subscriptions.SubscriptionProcessorManager;
|
import org.whispersystems.textsecuregcm.subscriptions.SubscriptionProcessorManager;
|
||||||
import org.whispersystems.textsecuregcm.util.ExactlySize;
|
import org.whispersystems.textsecuregcm.util.ExactlySize;
|
||||||
import org.whispersystems.textsecuregcm.util.ua.ClientPlatform;
|
|
||||||
import org.whispersystems.textsecuregcm.util.ua.UnrecognizedUserAgentException;
|
|
||||||
import org.whispersystems.textsecuregcm.util.ua.UserAgent;
|
|
||||||
import org.whispersystems.textsecuregcm.util.ua.UserAgentUtil;
|
|
||||||
|
|
||||||
@Path("/v1/subscription")
|
@Path("/v1/subscription")
|
||||||
@io.swagger.v3.oas.annotations.tags.Tag(name = "Subscriptions")
|
@io.swagger.v3.oas.annotations.tags.Tag(name = "Subscriptions")
|
||||||
|
@ -157,7 +152,7 @@ public class SubscriptionController {
|
||||||
this.bankMandateTranslator = Objects.requireNonNull(bankMandateTranslator);
|
this.bankMandateTranslator = Objects.requireNonNull(bankMandateTranslator);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<String, CurrencyConfiguration> buildCurrencyConfiguration(@Nullable final UserAgent userAgent) {
|
private Map<String, CurrencyConfiguration> buildCurrencyConfiguration() {
|
||||||
final List<SubscriptionProcessorManager> subscriptionProcessorManagers = List.of(stripeManager, braintreeManager);
|
final List<SubscriptionProcessorManager> subscriptionProcessorManagers = List.of(stripeManager, braintreeManager);
|
||||||
return oneTimeDonationConfiguration.currencies()
|
return oneTimeDonationConfiguration.currencies()
|
||||||
.entrySet().stream()
|
.entrySet().stream()
|
||||||
|
@ -178,7 +173,6 @@ public class SubscriptionController {
|
||||||
levelIdAndConfig -> levelIdAndConfig.getValue().getPrices().get(currency).amount()));
|
levelIdAndConfig -> levelIdAndConfig.getValue().getPrices().get(currency).amount()));
|
||||||
|
|
||||||
final List<String> supportedPaymentMethods = Arrays.stream(PaymentMethod.values())
|
final List<String> supportedPaymentMethods = Arrays.stream(PaymentMethod.values())
|
||||||
.filter(paymentMethod -> !excludePaymentMethod(userAgent, paymentMethod))
|
|
||||||
.filter(paymentMethod -> subscriptionProcessorManagers.stream()
|
.filter(paymentMethod -> subscriptionProcessorManagers.stream()
|
||||||
.anyMatch(manager -> manager.supportsPaymentMethod(paymentMethod)
|
.anyMatch(manager -> manager.supportsPaymentMethod(paymentMethod)
|
||||||
&& manager.getSupportedCurrenciesForPaymentMethod(paymentMethod).contains(currency)))
|
&& manager.getSupportedCurrenciesForPaymentMethod(paymentMethod).contains(currency)))
|
||||||
|
@ -194,18 +188,8 @@ public class SubscriptionController {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
// This logic to exclude some iOS client versions from receiving SEPA_DEBIT or IDEAL
|
|
||||||
// as a supported payment method can be removed after 01-23-24.
|
|
||||||
private boolean excludePaymentMethod(@Nullable final UserAgent userAgent, final PaymentMethod paymentMethod) {
|
|
||||||
return (paymentMethod == PaymentMethod.SEPA_DEBIT || paymentMethod == PaymentMethod.IDEAL)
|
|
||||||
&& userAgent != null
|
|
||||||
&& userAgent.getPlatform() == ClientPlatform.IOS
|
|
||||||
&& userAgent.getVersion().isLowerThanOrEqualTo(LAST_PROBLEMATIC_IOS_VERSION);
|
|
||||||
}
|
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
GetSubscriptionConfigurationResponse buildGetSubscriptionConfigurationResponse(final List<Locale> acceptableLanguages,
|
GetSubscriptionConfigurationResponse buildGetSubscriptionConfigurationResponse(final List<Locale> acceptableLanguages) {
|
||||||
final UserAgent userAgent) {
|
|
||||||
final Map<String, LevelConfiguration> levels = new HashMap<>();
|
final Map<String, LevelConfiguration> levels = new HashMap<>();
|
||||||
|
|
||||||
subscriptionConfiguration.getLevels().forEach((levelId, levelConfig) -> {
|
subscriptionConfiguration.getLevels().forEach((levelId, levelConfig) -> {
|
||||||
|
@ -233,7 +217,7 @@ public class SubscriptionController {
|
||||||
giftBadge,
|
giftBadge,
|
||||||
oneTimeDonationConfiguration.gift().expiration())));
|
oneTimeDonationConfiguration.gift().expiration())));
|
||||||
|
|
||||||
return new GetSubscriptionConfigurationResponse(buildCurrencyConfiguration(userAgent), levels, oneTimeDonationConfiguration.sepaMaximumEuros());
|
return new GetSubscriptionConfigurationResponse(buildCurrencyConfiguration(), levels, oneTimeDonationConfiguration.sepaMaximumEuros());
|
||||||
}
|
}
|
||||||
|
|
||||||
@DELETE
|
@DELETE
|
||||||
|
@ -574,18 +558,10 @@ public class SubscriptionController {
|
||||||
@GET
|
@GET
|
||||||
@Path("/configuration")
|
@Path("/configuration")
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
public CompletableFuture<Response> getConfiguration(@Context ContainerRequestContext containerRequestContext,
|
public CompletableFuture<Response> getConfiguration(@Context ContainerRequestContext containerRequestContext) {
|
||||||
@HeaderParam(HttpHeaders.USER_AGENT) final String userAgentString) {
|
|
||||||
return CompletableFuture.supplyAsync(() -> {
|
return CompletableFuture.supplyAsync(() -> {
|
||||||
List<Locale> acceptableLanguages = getAcceptableLanguagesForRequest(containerRequestContext);
|
List<Locale> acceptableLanguages = getAcceptableLanguagesForRequest(containerRequestContext);
|
||||||
|
return Response.ok(buildGetSubscriptionConfigurationResponse(acceptableLanguages)).build();
|
||||||
UserAgent userAgent;
|
|
||||||
try {
|
|
||||||
userAgent = UserAgentUtil.parseUserAgentString(userAgentString);
|
|
||||||
} catch (UnrecognizedUserAgentException e) {
|
|
||||||
userAgent = null;
|
|
||||||
}
|
|
||||||
return Response.ok(buildGetSubscriptionConfigurationResponse(acceptableLanguages, userAgent)).build();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,6 @@ import java.util.function.Predicate;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
import javax.ws.rs.client.Entity;
|
import javax.ws.rs.client.Entity;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
import org.apache.http.HttpHeaders;
|
|
||||||
import org.assertj.core.api.InstanceOfAssertFactories;
|
import org.assertj.core.api.InstanceOfAssertFactories;
|
||||||
import org.glassfish.jersey.server.ServerProperties;
|
import org.glassfish.jersey.server.ServerProperties;
|
||||||
import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory;
|
import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory;
|
||||||
|
@ -775,9 +774,8 @@ class SubscriptionControllerTest {
|
||||||
assertThat(response.getStatus()).isEqualTo(400);
|
assertThat(response.getStatus()).isEqualTo(400);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@Test
|
||||||
@MethodSource
|
void getSubscriptionConfiguration() {
|
||||||
void getSubscriptionConfiguration(final String userAgent, final boolean expectNonCardPaymentMethods) {
|
|
||||||
when(BADGE_TRANSLATOR.translate(any(), eq("B1"))).thenReturn(new Badge("B1", "cat1", "name1", "desc1",
|
when(BADGE_TRANSLATOR.translate(any(), eq("B1"))).thenReturn(new Badge("B1", "cat1", "name1", "desc1",
|
||||||
List.of("l", "m", "h", "x", "xx", "xxx"), "SVG",
|
List.of("l", "m", "h", "x", "xx", "xxx"), "SVG",
|
||||||
List.of(new BadgeSvg("sl", "sd"), new BadgeSvg("ml", "md"), new BadgeSvg("ll", "ld"))));
|
List.of(new BadgeSvg("sl", "sd"), new BadgeSvg("ml", "md"), new BadgeSvg("ll", "ld"))));
|
||||||
|
@ -799,7 +797,6 @@ class SubscriptionControllerTest {
|
||||||
|
|
||||||
GetSubscriptionConfigurationResponse response = RESOURCE_EXTENSION.target("/v1/subscription/configuration")
|
GetSubscriptionConfigurationResponse response = RESOURCE_EXTENSION.target("/v1/subscription/configuration")
|
||||||
.request()
|
.request()
|
||||||
.header(HttpHeaders.USER_AGENT, userAgent)
|
|
||||||
.get(GetSubscriptionConfigurationResponse.class);
|
.get(GetSubscriptionConfigurationResponse.class);
|
||||||
|
|
||||||
assertThat(response.sepaMaximumEuros()).isEqualTo("10000");
|
assertThat(response.sepaMaximumEuros()).isEqualTo("10000");
|
||||||
|
@ -856,7 +853,7 @@ class SubscriptionControllerTest {
|
||||||
List.of(BigDecimal.valueOf(5))));
|
List.of(BigDecimal.valueOf(5))));
|
||||||
assertThat(currency.subscription()).isEqualTo(
|
assertThat(currency.subscription()).isEqualTo(
|
||||||
Map.of("5", BigDecimal.valueOf(5), "15", BigDecimal.valueOf(15),"35", BigDecimal.valueOf(35)));
|
Map.of("5", BigDecimal.valueOf(5), "15", BigDecimal.valueOf(15),"35", BigDecimal.valueOf(35)));
|
||||||
final List<String> expectedPaymentMethods = expectNonCardPaymentMethods ? List.of("CARD", "SEPA_DEBIT", "IDEAL") : List.of("CARD");
|
final List<String> expectedPaymentMethods = List.of("CARD", "SEPA_DEBIT", "IDEAL");
|
||||||
assertThat(currency.supportedPaymentMethods()).isEqualTo(expectedPaymentMethods);
|
assertThat(currency.supportedPaymentMethods()).isEqualTo(expectedPaymentMethods);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -907,7 +904,6 @@ class SubscriptionControllerTest {
|
||||||
// subscription levels are Badge, while one-time levels are PurchasableBadge, which adds `duration`
|
// subscription levels are Badge, while one-time levels are PurchasableBadge, which adds `duration`
|
||||||
Map<String, Object> genericResponse = RESOURCE_EXTENSION.target("/v1/subscription/configuration")
|
Map<String, Object> genericResponse = RESOURCE_EXTENSION.target("/v1/subscription/configuration")
|
||||||
.request()
|
.request()
|
||||||
.header(HttpHeaders.USER_AGENT, userAgent)
|
|
||||||
.get(Map.class);
|
.get(Map.class);
|
||||||
|
|
||||||
assertThat(genericResponse.get("levels")).satisfies(levels -> {
|
assertThat(genericResponse.get("levels")).satisfies(levels -> {
|
||||||
|
@ -930,19 +926,6 @@ class SubscriptionControllerTest {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Stream<Arguments> getSubscriptionConfiguration() {
|
|
||||||
return Stream.of(
|
|
||||||
Arguments.of("Signal-iOS/6.44.0.8", false),
|
|
||||||
Arguments.of("Signal-iOS/6.45.0.0", true),
|
|
||||||
Arguments.of("Signal-iOS/6.45.0.2", true),
|
|
||||||
Arguments.of("Signal-iOS/6.46.0.0", true),
|
|
||||||
Arguments.of("Signal-Android/1.2.3", true),
|
|
||||||
Arguments.of(null, true),
|
|
||||||
Arguments.of("", true),
|
|
||||||
Arguments.of("definitely not a parseable user agent", true)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encapsulates {@code static} configuration, to keep the class header simpler and avoid illegal forward references
|
* Encapsulates {@code static} configuration, to keep the class header simpler and avoid illegal forward references
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in New Issue