diff --git a/Sources/Subscription/AccountManager.swift b/Sources/Subscription/AccountManager.swift index 9e2500d25..a5e04c6fe 100644 --- a/Sources/Subscription/AccountManager.swift +++ b/Sources/Subscription/AccountManager.swift @@ -23,6 +23,7 @@ public extension Notification.Name { static let accountDidSignIn = Notification.Name("com.duckduckgo.subscription.AccountDidSignIn") static let accountDidSignOut = Notification.Name("com.duckduckgo.subscription.AccountDidSignOut") static let entitlementsDidChange = Notification.Name("com.duckduckgo.subscription.EntitlementsDidChange") + static let subscriptionDidChange = Notification.Name("com.duckduckgo.subscription.SubscriptionDidChange") } public protocol AccountManagerKeychainAccessDelegate: AnyObject { @@ -245,20 +246,10 @@ public class AccountManager: AccountManaging { return .failure(EntitlementsError.noAccessToken) } - let cachedEntitlements: [Entitlement] = entitlementsCache.get() ?? [] - switch await AuthService.validateToken(accessToken: accessToken) { case .success(let response): let entitlements = response.account.entitlements - - if entitlements != cachedEntitlements { - if entitlements.isEmpty { - entitlementsCache.reset() - } else { - entitlementsCache.set(entitlements) - } - NotificationCenter.default.post(name: .entitlementsDidChange, object: self, userInfo: [UserDefaultsCacheKey.subscriptionEntitlements: entitlements]) - } + updateCache(with: entitlements) return .success(entitlements) case .failure(let error): @@ -267,6 +258,19 @@ public class AccountManager: AccountManaging { } } + public func updateCache(with entitlements: [Entitlement]) { + let cachedEntitlements: [Entitlement] = entitlementsCache.get() ?? [] + + if entitlements != cachedEntitlements { + if entitlements.isEmpty { + entitlementsCache.reset() + } else { + entitlementsCache.set(entitlements) + } + NotificationCenter.default.post(name: .entitlementsDidChange, object: self, userInfo: [UserDefaultsCacheKey.subscriptionEntitlements: entitlements]) + } + } + public func fetchEntitlements(cachePolicy: CachePolicy = .returnCacheDataElseLoad) async -> Result<[Entitlement], Error> { switch cachePolicy { diff --git a/Sources/Subscription/Flows/AppStore/AppStorePurchaseFlow.swift b/Sources/Subscription/Flows/AppStore/AppStorePurchaseFlow.swift index 16df59be3..b0bb18ed3 100644 --- a/Sources/Subscription/Flows/AppStore/AppStorePurchaseFlow.swift +++ b/Sources/Subscription/Flows/AppStore/AppStorePurchaseFlow.swift @@ -130,12 +130,15 @@ public final class AppStorePurchaseFlow { SubscriptionService.signOut() os_log(.info, log: .subscription, "[AppStorePurchaseFlow] completeSubscriptionPurchase") + let accountManager = AccountManager(subscriptionAppGroup: subscriptionAppGroup) - guard let accessToken = AccountManager(subscriptionAppGroup: subscriptionAppGroup).accessToken else { return .failure(.missingEntitlements) } + guard let accessToken = accountManager.accessToken else { return .failure(.missingEntitlements) } let result = await callWithRetries(retry: 5, wait: 2.0) { switch await SubscriptionService.confirmPurchase(accessToken: accessToken, signature: transactionJWS) { - case .success: + case .success(let confirmation): + SubscriptionService.updateCache(with: confirmation.subscription) + accountManager.updateCache(with: confirmation.entitlements) return true case .failure: return false diff --git a/Sources/Subscription/Services/Model/Subscription.swift b/Sources/Subscription/Services/Model/Subscription.swift index 391adaca5..703b1617a 100644 --- a/Sources/Subscription/Services/Model/Subscription.swift +++ b/Sources/Subscription/Services/Model/Subscription.swift @@ -18,7 +18,9 @@ import Foundation -public struct Subscription: Codable { +public typealias DDGSubscription = Subscription // to avoid conflicts when Combine is imported + +public struct Subscription: Codable, Equatable { public let productId: String public let name: String public let billingPeriod: BillingPeriod diff --git a/Sources/Subscription/Services/SubscriptionService.swift b/Sources/Subscription/Services/SubscriptionService.swift index e29e2cb86..6c7c9be17 100644 --- a/Sources/Subscription/Services/SubscriptionService.swift +++ b/Sources/Subscription/Services/SubscriptionService.swift @@ -56,15 +56,25 @@ public final class SubscriptionService: APIService { switch result { case .success(let subscriptionResponse): - let defaultExpiryDate = Date().addingTimeInterval(subscriptionCache.settings.defaultExpirationInterval) - let expiryDate = min(defaultExpiryDate, subscriptionResponse.expiresOrRenewsAt) - subscriptionCache.set(subscriptionResponse, expires: expiryDate) + updateCache(with: subscriptionResponse) return .success(subscriptionResponse) case .failure(let error): return .failure(.apiError(error)) } } + public static func updateCache(with subscription: Subscription) { + let cachedSubscription: Subscription? = subscriptionCache.get() + + if subscription != cachedSubscription { + let defaultExpiryDate = Date().addingTimeInterval(subscriptionCache.settings.defaultExpirationInterval) + let expiryDate = min(defaultExpiryDate, subscription.expiresOrRenewsAt) + + subscriptionCache.set(subscription, expires: expiryDate) + NotificationCenter.default.post(name: .subscriptionDidChange, object: self, userInfo: [UserDefaultsCacheKey.subscription: subscription]) + } + } + public static func getSubscription(accessToken: String, cachePolicy: CachePolicy = .returnCacheDataElseLoad) async -> Result { switch cachePolicy {