Asyncify monthlyDonation

This commit is contained in:
Max Radermacher 2025-06-16 23:55:57 -05:00 committed by GitHub
parent cd31be8f23
commit 04aa00a34f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -21,83 +21,64 @@ extension DonationPaymentDetailsViewController {
Logger.info("[Donations] Starting monthly donation")
Promise.wrapAsync {
try await DonationViewsUtil.wrapInProgressView(
from: self,
operation: firstly(on: DispatchQueue.sharedUserInitiated) { () -> Promise<Void> in
if let existingSubscriberId {
Logger.info("[Donations] Cancelling existing subscription")
return Promise.wrapAsync {
Task {
do {
try await DonationViewsUtil.wrapInProgressView(
from: self,
operation: {
if let existingSubscriberId {
Logger.info("[Donations] Cancelling existing subscription")
try await DonationSubscriptionManager.cancelSubscription(for: existingSubscriberId)
} else {
Logger.info("[Donations] No existing subscription to cancel")
}
} else {
Logger.info("[Donations] No existing subscription to cancel")
return Promise.value(())
}
}.then(on: DispatchQueue.sharedUserInitiated) { () -> Promise<Data> in
Logger.info("[Donations] Preparing new monthly subscription")
Logger.info("[Donations] Preparing new monthly subscription")
let subscriberId = try await DonationSubscriptionManager.prepareNewSubscription(currencyCode: currencyCode)
return Promise.wrapAsync {
try await DonationSubscriptionManager.prepareNewSubscription(currencyCode: currencyCode)
}
}.then(on: DispatchQueue.sharedUserInitiated) { subscriberId -> Promise<(Data, DonationSubscriptionManager.RecurringSubscriptionPaymentType)> in
Promise.wrapAsync { () -> String in
Logger.info("[Donations] Creating Signal payment method for new monthly subscription")
return try await Stripe.createSignalPaymentMethodForSubscription(subscriberId: subscriberId)
}.then(on: DispatchQueue.sharedUserInitiated) { clientSecret -> Promise<DonationSubscriptionManager.RecurringSubscriptionPaymentType> in
Logger.info("[Donations] Authorizing payment for new monthly subscription")
let clientSecret = try await Stripe.createSignalPaymentMethodForSubscription(subscriberId: subscriberId)
return Promise.wrapAsync {
return try await Stripe.setupNewSubscription(
clientSecret: clientSecret,
paymentMethod: validForm.stripePaymentMethod
)
}.then(on: DispatchQueue.sharedUserInitiated) { confirmedIntent -> Promise<Stripe.ConfirmedSetupIntent> in
if let redirectToUrl = confirmedIntent.redirectToUrl {
if case .ideal = validForm.donationPaymentMethod {
Logger.info("[Donations] Subscription requires iDEAL authentication. Presenting...")
let confirmedDonation = PendingMonthlyIDEALDonation(
subscriberId: subscriberId,
clientSecret: clientSecret,
setupIntentId: confirmedIntent.setupIntentId,
newSubscriptionLevel: newSubscriptionLevel,
oldSubscriptionLevel: priorSubscriptionLevel,
amount: self.donationAmount
)
SSKEnvironment.shared.databaseStorageRef.write { tx in
do {
try donationStore.setPendingSubscription(donation: confirmedDonation, tx: tx)
} catch {
owsFailDebug("[Donations] Failed to persist pending iDEAL subscription.")
}
Logger.info("[Donations] Authorizing payment for new monthly subscription")
let confirmedIntent = try await Stripe.setupNewSubscription(
clientSecret: clientSecret,
paymentMethod: validForm.stripePaymentMethod
)
if let redirectToUrl = confirmedIntent.redirectToUrl {
if case .ideal = validForm.donationPaymentMethod {
Logger.info("[Donations] Subscription requires iDEAL authentication. Presenting...")
let confirmedDonation = PendingMonthlyIDEALDonation(
subscriberId: subscriberId,
clientSecret: clientSecret,
setupIntentId: confirmedIntent.setupIntentId,
newSubscriptionLevel: newSubscriptionLevel,
oldSubscriptionLevel: priorSubscriptionLevel,
amount: self.donationAmount
)
await SSKEnvironment.shared.databaseStorageRef.awaitableWrite { tx in
do {
try donationStore.setPendingSubscription(donation: confirmedDonation, tx: tx)
} catch {
owsFailDebug("[Donations] Failed to persist pending iDEAL subscription.")
}
} else {
Logger.info("[Donations] Subscription requires 3DS authentication. Presenting...")
}
return self.show3DS(for: redirectToUrl)
.map(on: DispatchQueue.sharedUserInitiated) { _ in
return confirmedIntent
}
} else {
return Promise.value(confirmedIntent)
}
}.map { confirmedIntent in
switch validForm {
case .card:
return .creditOrDebitCard(paymentMethodId: confirmedIntent.paymentMethodId)
case .sepa:
return .sepa(paymentMethodId: confirmedIntent.paymentMethodId)
case .ideal:
return .ideal(setupIntentId: confirmedIntent.setupIntentId)
Logger.info("[Donations] Subscription requires 3DS authentication. Presenting...")
}
_ = try await self.show3DS(for: redirectToUrl).awaitable()
}
}.map(on: DispatchQueue.sharedUserInitiated) { paymentType -> (Data, DonationSubscriptionManager.RecurringSubscriptionPaymentType) in
(subscriberId, paymentType)
}
}.then(on: DispatchQueue.sharedUserInitiated) { (subscriberId, paymentType) in
return Promise.wrapAsync {
let paymentType: DonationSubscriptionManager.RecurringSubscriptionPaymentType
switch validForm {
case .card:
paymentType = .creditOrDebitCard(paymentMethodId: confirmedIntent.paymentMethodId)
case .sepa:
paymentType = .sepa(paymentMethodId: confirmedIntent.paymentMethodId)
case .ideal:
paymentType = .ideal(setupIntentId: confirmedIntent.setupIntentId)
}
try await DonationViewsUtil.completeMonthlyDonations(
subscriberId: subscriberId,
paymentType: paymentType,
@ -107,14 +88,13 @@ extension DonationPaymentDetailsViewController {
databaseStorage: SSKEnvironment.shared.databaseStorageRef
)
}
}.awaitable
)
}.done(on: DispatchQueue.main) { [weak self] in
Logger.info("[Donations] Monthly donation finished")
self?.onFinished(nil)
}.catch(on: DispatchQueue.main) { [weak self] error in
Logger.info("[Donations] Monthly donation UX dismissing w/error (might not be fatal)")
self?.onFinished(error)
)
Logger.info("[Donations] Monthly donation finished")
self.onFinished(nil)
} catch {
Logger.info("[Donations] Monthly donation UX dismissing w/error (might not be fatal)")
self.onFinished(error)
}
}
}
}