Skip to content
This repository was archived by the owner on Feb 24, 2025. It is now read-only.

Commit 9da0cee

Browse files
authoredMar 22, 2024··
Bug fixed for subscription restore from app store (#2478)
Task/Issue URL: https://app.asana.com/0/72649045549333/1206906054839368/f **Description**: Fix when the user is not getting any error if tries to restore a subscription that is not there / is expired from Settings > Subscription pro > I have a subscription > Restore
1 parent 9c8a825 commit 9da0cee

File tree

5 files changed

+231
-148
lines changed

5 files changed

+231
-148
lines changed
 

‎DuckDuckGo.xcodeproj/project.pbxproj

+25-1
Original file line numberDiff line numberDiff line change
@@ -3273,6 +3273,12 @@
32733273
EEDE50122BA360C80017F3C4 /* NetworkProtection+VPNAgentConvenienceInitializers.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEDE50102BA360C80017F3C4 /* NetworkProtection+VPNAgentConvenienceInitializers.swift */; };
32743274
EEF12E6F2A2111880023E6BF /* MacPacketTunnelProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEF12E6D2A2111880023E6BF /* MacPacketTunnelProvider.swift */; };
32753275
EEF53E182950CED5002D78F4 /* JSAlertViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEF53E172950CED5002D78F4 /* JSAlertViewModelTests.swift */; };
3276+
F1B33DF22BAD929D001128B3 /* SubscriptionAppStoreRestorer.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1B33DF12BAD929D001128B3 /* SubscriptionAppStoreRestorer.swift */; };
3277+
F1B33DF32BAD929D001128B3 /* SubscriptionAppStoreRestorer.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1B33DF12BAD929D001128B3 /* SubscriptionAppStoreRestorer.swift */; };
3278+
F1B33DF42BAD929D001128B3 /* SubscriptionAppStoreRestorer.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1B33DF12BAD929D001128B3 /* SubscriptionAppStoreRestorer.swift */; };
3279+
F1B33DF62BAD970E001128B3 /* SubscriptionErrorReporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1B33DF52BAD970E001128B3 /* SubscriptionErrorReporter.swift */; };
3280+
F1B33DF72BAD970E001128B3 /* SubscriptionErrorReporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1B33DF52BAD970E001128B3 /* SubscriptionErrorReporter.swift */; };
3281+
F1B33DF82BAD970E001128B3 /* SubscriptionErrorReporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1B33DF52BAD970E001128B3 /* SubscriptionErrorReporter.swift */; };
32763282
F1D43AEE2B98D8DF00BAB743 /* MainMenuActions+VanillaBrowser.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1D43AED2B98D8DF00BAB743 /* MainMenuActions+VanillaBrowser.swift */; };
32773283
F1D43AEF2B98D8DF00BAB743 /* MainMenuActions+VanillaBrowser.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1D43AED2B98D8DF00BAB743 /* MainMenuActions+VanillaBrowser.swift */; };
32783284
F1D43AF02B98D8DF00BAB743 /* MainMenuActions+VanillaBrowser.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1D43AED2B98D8DF00BAB743 /* MainMenuActions+VanillaBrowser.swift */; };
@@ -4666,6 +4672,8 @@
46664672
EEDE50102BA360C80017F3C4 /* NetworkProtection+VPNAgentConvenienceInitializers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NetworkProtection+VPNAgentConvenienceInitializers.swift"; sourceTree = "<group>"; };
46674673
EEF12E6D2A2111880023E6BF /* MacPacketTunnelProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MacPacketTunnelProvider.swift; sourceTree = "<group>"; };
46684674
EEF53E172950CED5002D78F4 /* JSAlertViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSAlertViewModelTests.swift; sourceTree = "<group>"; };
4675+
F1B33DF12BAD929D001128B3 /* SubscriptionAppStoreRestorer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscriptionAppStoreRestorer.swift; sourceTree = "<group>"; };
4676+
F1B33DF52BAD970E001128B3 /* SubscriptionErrorReporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscriptionErrorReporter.swift; sourceTree = "<group>"; };
46694677
F1D43AED2B98D8DF00BAB743 /* MainMenuActions+VanillaBrowser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "MainMenuActions+VanillaBrowser.swift"; sourceTree = "<group>"; };
46704678
F41D174025CB131900472416 /* NSColorExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSColorExtension.swift; sourceTree = "<group>"; };
46714679
F44C130125C2DA0400426E3E /* NSAppearanceExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSAppearanceExtension.swift; sourceTree = "<group>"; };
@@ -8430,7 +8438,7 @@
84308438
4BB88B4425B7B55C006F6B06 /* DebugUserScript.swift */,
84318439
856CADEF271710F400E79BB0 /* HoverUserScript.swift */,
84328440
4B2E7D6226FF9D6500D2DB17 /* PrintingUserScript.swift */,
8433-
1E0C72052ABC63BD00802009 /* SubscriptionPagesUserScript.swift */,
8441+
F1B33DF92BAD9C83001128B3 /* Subscription */,
84348442
1ED910D42B63BFB300936947 /* IdentityTheftRestorationPagesUserScript.swift */,
84358443
85AC3AEE25D5CE9800C7D2AA /* UserScripts.swift */,
84368444
);
@@ -8653,6 +8661,16 @@
86538661
path = JSAlert;
86548662
sourceTree = "<group>";
86558663
};
8664+
F1B33DF92BAD9C83001128B3 /* Subscription */ = {
8665+
isa = PBXGroup;
8666+
children = (
8667+
1E0C72052ABC63BD00802009 /* SubscriptionPagesUserScript.swift */,
8668+
F1B33DF12BAD929D001128B3 /* SubscriptionAppStoreRestorer.swift */,
8669+
F1B33DF52BAD970E001128B3 /* SubscriptionErrorReporter.swift */,
8670+
);
8671+
path = Subscription;
8672+
sourceTree = "<group>";
8673+
};
86568674
/* End PBXGroup section */
86578675

86588676
/* Begin PBXNativeTarget section */
@@ -10160,6 +10178,7 @@
1016010178
B65211262B29A42E00B30633 /* BookmarkStoreMock.swift in Sources */,
1016110179
3706FAF5293F65D500E42796 /* SafariVersionReader.swift in Sources */,
1016210180
3706FAF6293F65D500E42796 /* LoginFaviconView.swift in Sources */,
10181+
F1B33DF72BAD970E001128B3 /* SubscriptionErrorReporter.swift in Sources */,
1016310182
3706FEC0293F6EFF00E42796 /* BWRequest.swift in Sources */,
1016410183
3706FAF7293F65D500E42796 /* FireproofDomainsViewController.swift in Sources */,
1016510184
4BF0E5062AD2551A00FFEC9E /* NetworkProtectionPixelEvent.swift in Sources */,
@@ -10577,6 +10596,7 @@
1057710596
3706FC1B293F65D500E42796 /* TabCollectionViewModel+NSSecureCoding.swift in Sources */,
1057810597
3706FC1D293F65D500E42796 /* EmailManagerRequestDelegate.swift in Sources */,
1057910598
3706FC1E293F65D500E42796 /* ApplicationVersionReader.swift in Sources */,
10599+
F1B33DF32BAD929D001128B3 /* SubscriptionAppStoreRestorer.swift in Sources */,
1058010600
3706FC1F293F65D500E42796 /* BookmarksBarViewController.swift in Sources */,
1058110601
1DDC85042B83903E00670238 /* PreferencesWebTrackingProtectionView.swift in Sources */,
1058210602
3706FC20293F65D500E42796 /* PreferencesAutofillView.swift in Sources */,
@@ -11766,6 +11786,7 @@
1176611786
4B957B182AC7AE700062CA31 /* PreferencesDataClearingView.swift in Sources */,
1176711787
4B957B192AC7AE700062CA31 /* NSPasteboardExtension.swift in Sources */,
1176811788
4B957B1A2AC7AE700062CA31 /* OnboardingViewModel.swift in Sources */,
11789+
F1B33DF42BAD929D001128B3 /* SubscriptionAppStoreRestorer.swift in Sources */,
1176911790
4B957B1B2AC7AE700062CA31 /* ScriptSourceProviding.swift in Sources */,
1177011791
4B957B1C2AC7AE700062CA31 /* CoreDataBookmarkImporter.swift in Sources */,
1177111792
4B957B1D2AC7AE700062CA31 /* SuggestionViewModel.swift in Sources */,
@@ -11883,6 +11904,7 @@
1188311904
4B957B7E2AC7AE700062CA31 /* NetworkProtection+ConvenienceInitializers.swift in Sources */,
1188411905
7BA7CC502AD11F6F0042E5CE /* NetworkProtectionIPCTunnelController.swift in Sources */,
1188511906
4B957B7F2AC7AE700062CA31 /* NavigationActionExtension.swift in Sources */,
11907+
F1B33DF82BAD970E001128B3 /* SubscriptionErrorReporter.swift in Sources */,
1188611908
4B957B802AC7AE700062CA31 /* NSAlertExtension.swift in Sources */,
1188711909
4B957B812AC7AE700062CA31 /* ThirdPartyBrowser.swift in Sources */,
1188811910
4B957B822AC7AE700062CA31 /* SearchNonexistentDomainNavigationResponder.swift in Sources */,
@@ -12520,6 +12542,7 @@
1252012542
EE339228291BDEFD009F62C1 /* JSAlertController.swift in Sources */,
1252112543
4B9DB04A2A983B24000927DB /* NotificationService.swift in Sources */,
1252212544
3775912D29AAC72700E26367 /* SyncPreferences.swift in Sources */,
12545+
F1B33DF22BAD929D001128B3 /* SubscriptionAppStoreRestorer.swift in Sources */,
1252312546
1DB9618329F67F6200CF5568 /* FaviconNullStore.swift in Sources */,
1252412547
BB5789722B2CA70F0009DFE2 /* DataBrokerProtectionSubscriptionEventHandler.swift in Sources */,
1252512548
B693954F26F04BEB0015B914 /* PaddedImageButton.swift in Sources */,
@@ -12652,6 +12675,7 @@
1265212675
AA97BF4625135DD30014931A /* ApplicationDockMenu.swift in Sources */,
1265312676
4B8A4DFF27C83B29005F40E8 /* SaveIdentityViewController.swift in Sources */,
1265412677
1DDC84FB2B8356CE00670238 /* PreferencesDefaultBrowserView.swift in Sources */,
12678+
F1B33DF62BAD970E001128B3 /* SubscriptionErrorReporter.swift in Sources */,
1265512679
EEC589D92A4F1CE300BCD60C /* AppLauncher.swift in Sources */,
1265612680
4BA1A69B258B076900F6F690 /* FileStore.swift in Sources */,
1265712681
B6A9E47F26146A800067D1B9 /* PixelArguments.swift in Sources */,

‎DuckDuckGo/Preferences/View/PreferencesRootView.swift

+9-2
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ enum Preferences {
135135
}
136136

137137
#if SUBSCRIPTION
138-
// swiftlint:disable:next cyclomatic_complexity
138+
// swiftlint:disable:next cyclomatic_complexity function_body_length
139139
private func makeSubscriptionViewModel() -> PreferencesSubscriptionModel {
140140
let openURL: (URL) -> Void = { url in
141141
DispatchQueue.main.async {
@@ -179,7 +179,14 @@ enum Preferences {
179179

180180
let sheetActionHandler = SubscriptionAccessActionHandlers(restorePurchases: {
181181
if #available(macOS 12.0, *) {
182-
SubscriptionPagesUseSubscriptionFeature.startAppStoreRestoreFlow { _ in }
182+
Task {
183+
guard let mainViewController = WindowControllersManager.shared.lastKeyMainWindowController?.mainViewController,
184+
let windowControllerManager = WindowControllersManager.shared.lastKeyMainWindowController else {
185+
return
186+
}
187+
188+
await SubscriptionAppStoreRestorer.restoreAppStoreSubscription(mainViewController: mainViewController, windowController: windowControllerManager)
189+
}
183190
}
184191
},
185192
openURLHandler: openURL,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
//
2+
// SubscriptionAppStoreRestorer.swift
3+
//
4+
// Copyright © 2024 DuckDuckGo. All rights reserved.
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
//
18+
19+
import Foundation
20+
import Subscription
21+
import SubscriptionUI
22+
23+
@available(macOS 12.0, *)
24+
struct SubscriptionAppStoreRestorer {
25+
26+
static func restoreAppStoreSubscription(mainViewController: MainViewController, windowController: MainWindowController) async {
27+
28+
let progressViewController = await ProgressViewController(title: UserText.restoringSubscriptionTitle)
29+
defer {
30+
DispatchQueue.main.async {
31+
mainViewController.dismiss(progressViewController)
32+
}
33+
}
34+
35+
DispatchQueue.main.async {
36+
mainViewController.presentAsSheet(progressViewController)
37+
}
38+
39+
guard case .success = await PurchaseManager.shared.syncAppleIDAccount() else {
40+
return
41+
}
42+
43+
let result = await AppStoreRestoreFlow.restoreAccountFromPastPurchase(subscriptionAppGroup: Bundle.main.appGroup(bundle: .subs))
44+
45+
switch result {
46+
case .success:
47+
DailyPixel.fire(pixel: .privacyProRestorePurchaseStoreSuccess, frequency: .dailyAndCount)
48+
49+
case .failure(let error):
50+
switch error {
51+
case .missingAccountOrTransactions: break
52+
default:
53+
DailyPixel.fire(pixel: .privacyProRestorePurchaseStoreFailureOther, frequency: .dailyAndCount)
54+
}
55+
56+
switch error {
57+
case .missingAccountOrTransactions:
58+
SubscriptionErrorReporter.report(subscriptionActivationError: .subscriptionNotFound)
59+
await windowController.showSubscriptionNotFoundAlert()
60+
case .subscriptionExpired:
61+
SubscriptionErrorReporter.report(subscriptionActivationError: .subscriptionExpired)
62+
await windowController.showSubscriptionInactiveAlert()
63+
case .pastTransactionAuthenticationError, .failedToObtainAccessToken, .failedToFetchAccountDetails, .failedToFetchSubscriptionDetails:
64+
SubscriptionErrorReporter.report(subscriptionActivationError: .generalError)
65+
await windowController.showSomethingWentWrongAlert()
66+
}
67+
}
68+
}
69+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
//
2+
// SubscriptionErrorReporter.swift
3+
//
4+
// Copyright © 2024 DuckDuckGo. All rights reserved.
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
//
18+
19+
import Foundation
20+
import Common
21+
22+
enum SubscriptionError: Error {
23+
case purchaseFailed,
24+
missingEntitlements,
25+
failedToGetSubscriptionOptions,
26+
failedToSetSubscription,
27+
failedToRestoreFromEmail,
28+
failedToRestoreFromEmailSubscriptionInactive,
29+
failedToRestorePastPurchase,
30+
subscriptionNotFound,
31+
subscriptionExpired,
32+
hasActiveSubscription,
33+
cancelledByUser,
34+
accountCreationFailed,
35+
activeSubscriptionAlreadyPresent,
36+
generalError
37+
}
38+
39+
struct SubscriptionErrorReporter {
40+
41+
// swiftlint:disable:next cyclomatic_complexity
42+
static func report(subscriptionActivationError: SubscriptionError) {
43+
44+
os_log(.error, log: .subscription, "Subscription purchase error: %{public}s", subscriptionActivationError.localizedDescription)
45+
46+
var isStoreError = false
47+
var isBackendError = false
48+
49+
switch subscriptionActivationError {
50+
case .purchaseFailed:
51+
isStoreError = true
52+
case .missingEntitlements:
53+
isBackendError = true
54+
case .failedToGetSubscriptionOptions:
55+
isStoreError = true
56+
case .failedToSetSubscription:
57+
isBackendError = true
58+
case .failedToRestoreFromEmail, .failedToRestoreFromEmailSubscriptionInactive:
59+
isBackendError = true
60+
case .failedToRestorePastPurchase:
61+
isStoreError = true
62+
case .subscriptionNotFound:
63+
DailyPixel.fire(pixel: .privacyProRestorePurchaseStoreFailureNotFound, frequency: .dailyAndCount)
64+
isStoreError = true
65+
case .subscriptionExpired:
66+
isStoreError = true
67+
case .hasActiveSubscription:
68+
isStoreError = true
69+
isBackendError = true
70+
case .cancelledByUser: break
71+
case .accountCreationFailed:
72+
DailyPixel.fire(pixel: .privacyProPurchaseFailureAccountNotCreated, frequency: .dailyAndCount)
73+
case .activeSubscriptionAlreadyPresent: break
74+
case .generalError: break
75+
}
76+
77+
if isStoreError {
78+
DailyPixel.fire(pixel: .privacyProPurchaseFailureStoreError, frequency: .dailyAndCount)
79+
}
80+
81+
if isBackendError {
82+
DailyPixel.fire(pixel: .privacyProPurchaseFailureBackendError, frequency: .dailyAndCount)
83+
}
84+
}
85+
}

0 commit comments

Comments
 (0)
This repository has been archived.