Add backupSubscription field to configuration object.

This commit is contained in:
Alex Hart 2024-04-18 11:12:01 -03:00 committed by Greyson Parrelli
parent d9e9fe1d6a
commit 735a8e680c
7 changed files with 46 additions and 39 deletions

View file

@ -8,7 +8,7 @@ import org.thoughtcrime.securesms.badges.models.Badge
import org.thoughtcrime.securesms.components.settings.app.subscription.getGiftBadgeAmounts
import org.thoughtcrime.securesms.components.settings.app.subscription.getGiftBadges
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
import org.whispersystems.signalservice.internal.push.DonationsConfiguration
import org.whispersystems.signalservice.internal.push.SubscriptionsConfiguration
import java.util.Currency
import java.util.Locale
@ -28,7 +28,7 @@ class GiftFlowRepository {
.getDonationsConfiguration(Locale.getDefault())
}
.flatMap { it.flattenResult() }
.map { DonationsConfiguration.GIFT_LEVEL to it.getGiftBadges().first() }
.map { SubscriptionsConfiguration.GIFT_LEVEL to it.getGiftBadges().first() }
.subscribeOn(Schedulers.io())
}

View file

@ -4,11 +4,11 @@ import org.signal.core.util.money.FiatMoney
import org.signal.core.util.money.PlatformCurrencyUtil
import org.thoughtcrime.securesms.badges.Badges
import org.thoughtcrime.securesms.badges.models.Badge
import org.whispersystems.signalservice.internal.push.DonationsConfiguration
import org.whispersystems.signalservice.internal.push.DonationsConfiguration.BOOST_LEVEL
import org.whispersystems.signalservice.internal.push.DonationsConfiguration.GIFT_LEVEL
import org.whispersystems.signalservice.internal.push.DonationsConfiguration.LevelConfiguration
import org.whispersystems.signalservice.internal.push.DonationsConfiguration.SUBSCRIPTION_LEVELS
import org.whispersystems.signalservice.internal.push.SubscriptionsConfiguration
import org.whispersystems.signalservice.internal.push.SubscriptionsConfiguration.BOOST_LEVEL
import org.whispersystems.signalservice.internal.push.SubscriptionsConfiguration.GIFT_LEVEL
import org.whispersystems.signalservice.internal.push.SubscriptionsConfiguration.LevelConfiguration
import org.whispersystems.signalservice.internal.push.SubscriptionsConfiguration.SUBSCRIPTION_LEVELS
import java.math.BigDecimal
import java.util.Currency
@ -26,7 +26,7 @@ private const val SEPA_DEBIT = "SEPA_DEBIT"
* @param level The subscription level to get amounts for
* @param paymentMethodAvailability Predicate object which checks whether different payment methods are availble.
*/
fun DonationsConfiguration.getSubscriptionAmounts(
fun SubscriptionsConfiguration.getSubscriptionAmounts(
level: Int,
paymentMethodAvailability: PaymentMethodAvailability = DefaultPaymentMethodAvailability
): Set<FiatMoney> {
@ -41,7 +41,7 @@ fun DonationsConfiguration.getSubscriptionAmounts(
/**
* Currently, we only support a single gift badge at level GIFT_LEVEL
*/
fun DonationsConfiguration.getGiftBadges(): List<Badge> {
fun SubscriptionsConfiguration.getGiftBadges(): List<Badge> {
val configuration = levels[GIFT_LEVEL]
return listOfNotNull(configuration?.badge?.let { Badges.fromServiceBadge(it) })
}
@ -49,7 +49,7 @@ fun DonationsConfiguration.getGiftBadges(): List<Badge> {
/**
* Currently, we only support a single gift badge amount per currency
*/
fun DonationsConfiguration.getGiftBadgeAmounts(paymentMethodAvailability: PaymentMethodAvailability = DefaultPaymentMethodAvailability): Map<Currency, FiatMoney> {
fun SubscriptionsConfiguration.getGiftBadgeAmounts(paymentMethodAvailability: PaymentMethodAvailability = DefaultPaymentMethodAvailability): Map<Currency, FiatMoney> {
return getFilteredCurrencies(paymentMethodAvailability).filter {
it.value.oneTime[GIFT_LEVEL]?.isNotEmpty() == true
}.mapKeys {
@ -62,12 +62,12 @@ fun DonationsConfiguration.getGiftBadgeAmounts(paymentMethodAvailability: Paymen
/**
* Currently, we only support a single boost badge at level BOOST_LEVEL
*/
fun DonationsConfiguration.getBoostBadges(): List<Badge> {
fun SubscriptionsConfiguration.getBoostBadges(): List<Badge> {
val configuration = levels[BOOST_LEVEL]
return listOfNotNull(configuration?.badge?.let { Badges.fromServiceBadge(it) })
}
fun DonationsConfiguration.getBoostAmounts(paymentMethodAvailability: PaymentMethodAvailability = DefaultPaymentMethodAvailability): Map<Currency, List<FiatMoney>> {
fun SubscriptionsConfiguration.getBoostAmounts(paymentMethodAvailability: PaymentMethodAvailability = DefaultPaymentMethodAvailability): Map<Currency, List<FiatMoney>> {
return getFilteredCurrencies(paymentMethodAvailability).filter {
it.value.oneTime[BOOST_LEVEL]?.isNotEmpty() == true
}.mapKeys {
@ -77,12 +77,12 @@ fun DonationsConfiguration.getBoostAmounts(paymentMethodAvailability: PaymentMet
}
}
fun DonationsConfiguration.getBadge(level: Int): Badge {
fun SubscriptionsConfiguration.getBadge(level: Int): Badge {
require(level == GIFT_LEVEL || level == BOOST_LEVEL || SUBSCRIPTION_LEVELS.contains(level))
return Badges.fromServiceBadge(levels[level]!!.badge)
}
fun DonationsConfiguration.getSubscriptionLevels(): Map<Int, LevelConfiguration> {
fun SubscriptionsConfiguration.getSubscriptionLevels(): Map<Int, LevelConfiguration> {
return levels.filterKeys { SUBSCRIPTION_LEVELS.contains(it) }.toSortedMap()
}
@ -90,17 +90,17 @@ fun DonationsConfiguration.getSubscriptionLevels(): Map<Int, LevelConfiguration>
* Get a map describing the minimum donation amounts per currency.
* This returns only the currencies available to the user.
*/
fun DonationsConfiguration.getMinimumDonationAmounts(paymentMethodAvailability: PaymentMethodAvailability = DefaultPaymentMethodAvailability): Map<Currency, FiatMoney> {
fun SubscriptionsConfiguration.getMinimumDonationAmounts(paymentMethodAvailability: PaymentMethodAvailability = DefaultPaymentMethodAvailability): Map<Currency, FiatMoney> {
return getFilteredCurrencies(paymentMethodAvailability)
.mapKeys { Currency.getInstance(it.key.uppercase()) }
.mapValues { FiatMoney(it.value.minimum, it.key) }
}
fun DonationsConfiguration.getAvailablePaymentMethods(currencyCode: String): Set<String> {
fun SubscriptionsConfiguration.getAvailablePaymentMethods(currencyCode: String): Set<String> {
return currencies[currencyCode.lowercase()]?.supportedPaymentMethods ?: emptySet()
}
private fun DonationsConfiguration.getFilteredCurrencies(paymentMethodAvailability: PaymentMethodAvailability): Map<String, DonationsConfiguration.CurrencyConfiguration> {
private fun SubscriptionsConfiguration.getFilteredCurrencies(paymentMethodAvailability: PaymentMethodAvailability): Map<String, SubscriptionsConfiguration.CurrencyConfiguration> {
val userPaymentMethods = paymentMethodAvailability.toSet()
val availableCurrencyCodes = PlatformCurrencyUtil.getAvailableCurrencyCodes()
return currencies.filter { (code, config) ->

View file

@ -5,7 +5,7 @@ import org.signal.core.util.money.FiatMoney
import org.thoughtcrime.securesms.components.settings.app.subscription.getAvailablePaymentMethods
import org.thoughtcrime.securesms.payments.currency.CurrencyUtil
import org.whispersystems.signalservice.api.services.DonationsService
import org.whispersystems.signalservice.internal.push.DonationsConfiguration
import org.whispersystems.signalservice.internal.push.SubscriptionsConfiguration
import java.util.Locale
class GatewaySelectorRepository(
@ -18,10 +18,10 @@ class GatewaySelectorRepository(
.map { configuration ->
val available = configuration.getAvailablePaymentMethods(currencyCode).map {
when (it) {
DonationsConfiguration.PAYPAL -> listOf(GatewayResponse.Gateway.PAYPAL)
DonationsConfiguration.CARD -> listOf(GatewayResponse.Gateway.CREDIT_CARD, GatewayResponse.Gateway.GOOGLE_PAY)
DonationsConfiguration.SEPA_DEBIT -> listOf(GatewayResponse.Gateway.SEPA_DEBIT)
DonationsConfiguration.IDEAL -> listOf(GatewayResponse.Gateway.IDEAL)
SubscriptionsConfiguration.PAYPAL -> listOf(GatewayResponse.Gateway.PAYPAL)
SubscriptionsConfiguration.CARD -> listOf(GatewayResponse.Gateway.CREDIT_CARD, GatewayResponse.Gateway.GOOGLE_PAY)
SubscriptionsConfiguration.SEPA_DEBIT -> listOf(GatewayResponse.Gateway.SEPA_DEBIT)
SubscriptionsConfiguration.IDEAL -> listOf(GatewayResponse.Gateway.IDEAL)
else -> listOf()
}
}.flatten().toSet()

View file

@ -12,20 +12,20 @@ import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
import org.whispersystems.signalservice.internal.push.DonationsConfiguration
import org.whispersystems.signalservice.internal.push.SubscriptionsConfiguration
import org.whispersystems.signalservice.internal.util.JsonUtil
import java.util.Currency
@RunWith(RobolectricTestRunner::class)
@Config(application = Application::class)
class DonationsConfigurationExtensionsKtTest {
class SubscriptionsConfigurationExtensionsKtTest {
private val testData: String = javaClass.classLoader!!.getResourceAsStream("donations_configuration_test_data.json").bufferedReader().readText()
private val testSubject = JsonUtil.fromJson(testData, DonationsConfiguration::class.java)
private val testSubject = JsonUtil.fromJson(testData, SubscriptionsConfiguration::class.java)
@Test
fun `Given all methods are available, when I getSubscriptionAmounts, then I expect all currencies`() {
val subscriptionPrices = testSubject.getSubscriptionAmounts(DonationsConfiguration.SUBSCRIPTION_LEVELS.first(), AllPaymentMethodsAvailability)
val subscriptionPrices = testSubject.getSubscriptionAmounts(SubscriptionsConfiguration.SUBSCRIPTION_LEVELS.first(), AllPaymentMethodsAvailability)
assertEquals(3, subscriptionPrices.size)
assertTrue(subscriptionPrices.map { it.currency.currencyCode }.containsAll(setOf("JPY", "BIF", "USD")))
@ -33,7 +33,7 @@ class DonationsConfigurationExtensionsKtTest {
@Test
fun `Given only PayPal available, when I getSubscriptionAmounts, then I expect BIF and JPY`() {
val subscriptionPrices = testSubject.getSubscriptionAmounts(DonationsConfiguration.SUBSCRIPTION_LEVELS.first(), PayPalOnly)
val subscriptionPrices = testSubject.getSubscriptionAmounts(SubscriptionsConfiguration.SUBSCRIPTION_LEVELS.first(), PayPalOnly)
assertEquals(2, subscriptionPrices.size)
assertTrue(subscriptionPrices.map { it.currency.currencyCode }.containsAll(setOf("JPY", "BIF")))
@ -41,7 +41,7 @@ class DonationsConfigurationExtensionsKtTest {
@Test
fun `Given only Card available, when I getSubscriptionAmounts, then I expect BIF and USD`() {
val subscriptionPrices = testSubject.getSubscriptionAmounts(DonationsConfiguration.SUBSCRIPTION_LEVELS.first(), CardOnly)
val subscriptionPrices = testSubject.getSubscriptionAmounts(SubscriptionsConfiguration.SUBSCRIPTION_LEVELS.first(), CardOnly)
assertEquals(2, subscriptionPrices.size)
assertTrue(subscriptionPrices.map { it.currency.currencyCode }.containsAll(setOf("USD", "BIF")))
@ -76,7 +76,7 @@ class DonationsConfigurationExtensionsKtTest {
val subscriptionLevels = testSubject.getSubscriptionLevels()
assertEquals(3, subscriptionLevels.size)
assertEquals(DonationsConfiguration.SUBSCRIPTION_LEVELS, subscriptionLevels.keys)
assertEquals(SubscriptionsConfiguration.SUBSCRIPTION_LEVELS, subscriptionLevels.keys)
subscriptionLevels.keys.fold(0) { acc, i ->
assertTrue(acc < i)
i
@ -165,7 +165,7 @@ class DonationsConfigurationExtensionsKtTest {
fun `Given GIFT_LEVEL, When I getBadge, then I expect the gift badge`() {
mockkStatic(ApplicationDependencies::class) {
every { ApplicationDependencies.getApplication() } returns ApplicationProvider.getApplicationContext()
val badge = testSubject.getBadge(DonationsConfiguration.GIFT_LEVEL)
val badge = testSubject.getBadge(SubscriptionsConfiguration.GIFT_LEVEL)
assertTrue(badge.isGift())
}
@ -175,7 +175,7 @@ class DonationsConfigurationExtensionsKtTest {
fun `Given BOOST_LEVEL, When I getBadge, then I expect the boost badge`() {
mockkStatic(ApplicationDependencies::class) {
every { ApplicationDependencies.getApplication() } returns ApplicationProvider.getApplicationContext()
val badge = testSubject.getBadge(DonationsConfiguration.BOOST_LEVEL)
val badge = testSubject.getBadge(SubscriptionsConfiguration.BOOST_LEVEL)
assertTrue(badge.isBoost())
}
@ -185,7 +185,7 @@ class DonationsConfigurationExtensionsKtTest {
fun `Given a sub level, When I getBadge, then I expect a sub badge`() {
mockkStatic(ApplicationDependencies::class) {
every { ApplicationDependencies.getApplication() } returns ApplicationProvider.getApplicationContext()
val badge = testSubject.getBadge(DonationsConfiguration.SUBSCRIPTION_LEVELS.first())
val badge = testSubject.getBadge(SubscriptionsConfiguration.SUBSCRIPTION_LEVELS.first())
assertTrue(badge.isSubscription())
}

View file

@ -19,7 +19,7 @@ import org.whispersystems.signalservice.internal.ServiceResponse;
import org.whispersystems.signalservice.internal.configuration.SignalServiceConfiguration;
import org.whispersystems.signalservice.internal.push.BankMandate;
import org.whispersystems.signalservice.internal.push.DonationProcessor;
import org.whispersystems.signalservice.internal.push.DonationsConfiguration;
import org.whispersystems.signalservice.internal.push.SubscriptionsConfiguration;
import org.whispersystems.signalservice.internal.push.PushServiceSocket;
import java.io.IOException;
@ -42,7 +42,7 @@ public class DonationsService {
private final PushServiceSocket pushServiceSocket;
private final AtomicReference<CacheEntry<DonationsConfiguration>> donationsConfigurationCache = new AtomicReference<>(null);
private final AtomicReference<CacheEntry<SubscriptionsConfiguration>> donationsConfigurationCache = new AtomicReference<>(null);
private final AtomicReference<CacheEntry<BankMandate>> sepaBankMandateCache = new AtomicReference<>(null);
private static class CacheEntry<T> {
@ -111,7 +111,7 @@ public class DonationsService {
return wrapInServiceResponse(() -> new Pair<>(pushServiceSocket.submitBoostReceiptCredentials(paymentIntentId, receiptCredentialRequest, processor), 200));
}
public ServiceResponse<DonationsConfiguration> getDonationsConfiguration(Locale locale) {
public ServiceResponse<SubscriptionsConfiguration> getDonationsConfiguration(Locale locale) {
return getCachedValue(
locale,
donationsConfigurationCache,

View file

@ -1348,11 +1348,11 @@ public class PushServiceSocket {
/**
* Get the DonationsConfiguration pointed at by /v1/subscriptions/configuration
*/
public DonationsConfiguration getDonationsConfiguration(Locale locale) throws IOException {
public SubscriptionsConfiguration getDonationsConfiguration(Locale locale) throws IOException {
Map<String, String> headers = Collections.singletonMap("Accept-Language", locale.getLanguage() + "-" + locale.getCountry());
String result = makeServiceRequestWithoutAuthentication(DONATIONS_CONFIGURATION, "GET", null, headers, NO_HANDLER);
return JsonUtil.fromJson(result, DonationsConfiguration.class);
return JsonUtil.fromJson(result, SubscriptionsConfiguration.class);
}
/**

View file

@ -14,7 +14,7 @@ import java.util.Set;
/**
* Response JSON for a call to /v1/subscriptions/configuration
*/
public class DonationsConfiguration {
public class SubscriptionsConfiguration {
public static final String PAYPAL = "PAYPAL";
public static final String CARD = "CARD";
@ -44,6 +44,9 @@ public class DonationsConfiguration {
@JsonProperty("subscription")
private Map<Integer, BigDecimal> subscription;
@JsonProperty("backupSubscription")
private Map<Integer, BigDecimal> backupSubscription;
@JsonProperty("supportedPaymentMethods")
private Set<String> supportedPaymentMethods;
@ -59,6 +62,10 @@ public class DonationsConfiguration {
return subscription;
}
public Map<Integer, BigDecimal> getBackupSubscription() {
return backupSubscription;
}
public Set<String> getSupportedPaymentMethods() {
return supportedPaymentMethods;
}