Skip to content

Commit 475aaea

Browse files
[REST API] Initial support for WPCom account creation during Jetpack setup (#14431)
2 parents 77d4cfa + 8f5e0d6 commit 475aaea

File tree

10 files changed

+119
-19
lines changed

10 files changed

+119
-19
lines changed

Experiments/Experiments/DefaultFeatureFlagService.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ public struct DefaultFeatureFlagService: FeatureFlagService {
9595
return false
9696
case .sendReceiptsForPointOfSale:
9797
return false
98+
case .jetpackSetupWPComAccountCreation:
99+
return buildConfig == .localDeveloper || buildConfig == .alpha
98100
default:
99101
return true
100102
}

Experiments/Experiments/FeatureFlag.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,4 +203,8 @@ public enum FeatureFlag: Int {
203203
/// Adds support for sending receipts after the payment for POS
204204
///
205205
case sendReceiptsForPointOfSale
206+
207+
/// Enables WPCom account creation during Jetpack setup
208+
///
209+
case jetpackSetupWPComAccountCreation
206210
}

Podfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ target 'WooCommerce' do
9393
# To allow pod to pick up beta versions use -beta. E.g., 1.1.7-beta.1
9494
# pod 'WordPressAuthenticator', '~> 9.10.0'
9595
# pod 'WordPressAuthenticator', git: 'https://github.com/wordpress-mobile/WordPressAuthenticator-iOS.git', branch: ''
96-
pod 'WordPressAuthenticator', git: 'https://github.com/wordpress-mobile/WordPressAuthenticator-iOS.git', commit: 'f591b6e0442f9f153ad3842efdb8c81d26235c44'
96+
pod 'WordPressAuthenticator', git: 'https://github.com/wordpress-mobile/WordPressAuthenticator-iOS.git', commit: 'cd53ee3d6209619be6f7bb61f1707fbebf77798c'
9797
# pod 'WordPressAuthenticator', path: '../WordPressAuthenticator-iOS'
9898

9999
wordpress_shared

Podfile.lock

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,10 @@ PODS:
2828
- Gridicons (~> 1.0)
2929
- "NSURL+IDN (= 0.4)"
3030
- SVProgressHUD (~> 2.2.5)
31-
- WordPressKit (~> 17.0)
31+
- WordPressKit (~> 17.3)
3232
- WordPressShared (~> 2.1-beta)
3333
- WordPressUI (~> 1.7-beta)
34-
- WordPressKit (17.2.0):
34+
- WordPressKit (17.3.0):
3535
- NSObject-SafeExpectations (~> 0.0.4)
3636
- UIDeviceIdentifier (~> 2.0)
3737
- WordPressShared (~> 2.0-beta)
@@ -67,16 +67,14 @@ DEPENDENCIES:
6767
- StripeTerminal (~> 3.9.1)
6868
- SwiftLint (= 0.54.0)
6969
- WordPress-Editor-iOS (~> 1.19)
70-
- WordPressAuthenticator (from `https://github.com/wordpress-mobile/WordPressAuthenticator-iOS.git`, commit `f591b6e0442f9f153ad3842efdb8c81d26235c44`)
70+
- WordPressAuthenticator (from `https://github.com/wordpress-mobile/WordPressAuthenticator-iOS.git`, commit `cd53ee3d6209619be6f7bb61f1707fbebf77798c`)
7171
- WordPressShared (~> 2.1)
7272
- WordPressUI (~> 1.15)
7373
- Wormholy (~> 1.6.6)
7474
- WPMediaPicker (~> 1.8)
7575
- ZendeskSupportSDK (~> 9.0.0)
7676

7777
SPEC REPOS:
78-
https://github.com/wordpress-mobile/cocoapods-specs.git:
79-
- WordPressKit
8078
trunk:
8179
- Alamofire
8280
- Automattic-Tracks-iOS
@@ -95,6 +93,7 @@ SPEC REPOS:
9593
- UIDeviceIdentifier
9694
- WordPress-Aztec-iOS
9795
- WordPress-Editor-iOS
96+
- WordPressKit
9897
- WordPressShared
9998
- WordPressUI
10099
- Wormholy
@@ -110,12 +109,12 @@ SPEC REPOS:
110109

111110
EXTERNAL SOURCES:
112111
WordPressAuthenticator:
113-
:commit: f591b6e0442f9f153ad3842efdb8c81d26235c44
112+
:commit: cd53ee3d6209619be6f7bb61f1707fbebf77798c
114113
:git: https://github.com/wordpress-mobile/WordPressAuthenticator-iOS.git
115114

116115
CHECKOUT OPTIONS:
117116
WordPressAuthenticator:
118-
:commit: f591b6e0442f9f153ad3842efdb8c81d26235c44
117+
:commit: cd53ee3d6209619be6f7bb61f1707fbebf77798c
119118
:git: https://github.com/wordpress-mobile/WordPressAuthenticator-iOS.git
120119

121120
SPEC CHECKSUMS:
@@ -136,8 +135,8 @@ SPEC CHECKSUMS:
136135
UIDeviceIdentifier: 442b65b4ff1832d4ca9c2a157815cb29ad981b17
137136
WordPress-Aztec-iOS: 8eaa928fb3a5694924ed3befac64beaae5656e12
138137
WordPress-Editor-iOS: 98ce1fc542c3a09e48ddc9423405b1d1e48240f1
139-
WordPressAuthenticator: d151cc7ebc1cfcbf5c28bb2c9afe760a75b49ba6
140-
WordPressKit: de44094b3be8998504a3a57700bc3e96e3b46f57
138+
WordPressAuthenticator: 0f4f47d6f71cfa763cb636876d69170a3c710002
139+
WordPressKit: faf8c6de7c2acfe71cf95b4db896901060967089
141140
WordPressShared: 0aa459e5257a77184db87805a998f447443c9706
142141
WordPressUI: 700e3ec5a9f77b6920c8104c338c85788036ab3c
143142
Wormholy: 09da0b876f9276031fd47383627cb75e194fc068
@@ -151,6 +150,6 @@ SPEC CHECKSUMS:
151150
ZendeskSupportProvidersSDK: 281acf2bb731d2a67f913cfe653ed0da9f5b2f42
152151
ZendeskSupportSDK: b512cfc74b6bf8490e589f02cf52e27ed4f2bebe
153152

154-
PODFILE CHECKSUM: 51f5cabba416d490c8f90395fa0a86fde13dd931
153+
PODFILE CHECKSUM: f02fa3bd6b4c798923cccc4fbe03de910e60891b
155154

156155
COCOAPODS: 1.16.1

WooCommerce/Classes/Authentication/WPComLogin/WPComEmailLoginView.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ struct WPComEmailLoginView_Previews: PreviewProvider {
134134
static var previews: some View {
135135
WPComEmailLoginView(viewModel: .init(siteURL: "https://example.com",
136136
requiresConnectionOnly: true,
137+
allowAccountCreation: false,
137138
onPasswordUIRequest: { _ in },
138139
onMagicLinkUIRequest: { _ in },
139140
onError: { _ in }))

WooCommerce/Classes/Authentication/WPComLogin/WPComEmailLoginViewModel.swift

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,17 @@ import Combine
22
import UIKit
33
import WordPressAuthenticator
44
import protocol WooFoundation.Analytics
5+
import enum WordPressKit.WordPressAPIError
6+
import struct WordPressKit.WordPressComRestApiEndpointError
57

68
/// A protocol used to mock `WordPressComAccountService` for unit tests.
79
protocol WordPressComAccountServiceProtocol {
810
func isPasswordlessAccount(username: String, success: @escaping (Bool) -> Void, failure: @escaping (Error) -> Void)
9-
func requestAuthenticationLink(for email: String, jetpackLogin: Bool, success: @escaping () -> Void, failure: @escaping (Error) -> Void)
11+
func requestAuthenticationLink(for email: String,
12+
jetpackLogin: Bool,
13+
createAccountIfNotFound: Bool,
14+
success: @escaping () -> Void,
15+
failure: @escaping (Error) -> Void)
1016
}
1117

1218
/// Conformance
@@ -21,6 +27,7 @@ final class WPComEmailLoginViewModel: ObservableObject {
2127

2228
let termsAttributedString: NSAttributedString
2329

30+
private let allowAccountCreation: Bool
2431
private let accountService: WordPressComAccountServiceProtocol
2532
private let analytics: Analytics
2633
private let onPasswordUIRequest: (String) -> Void
@@ -31,12 +38,14 @@ final class WPComEmailLoginViewModel: ObservableObject {
3138

3239
init(siteURL: String,
3340
requiresConnectionOnly: Bool,
41+
allowAccountCreation: Bool,
3442
debounceDuration: Double = Constants.fieldDebounceDuration,
3543
accountService: WordPressComAccountServiceProtocol = WordPressComAccountService(),
3644
analytics: Analytics = ServiceLocator.analytics,
3745
onPasswordUIRequest: @escaping (String) -> Void,
3846
onMagicLinkUIRequest: @escaping (String) -> Void,
3947
onError: @escaping (String) -> Void) {
48+
self.allowAccountCreation = allowAccountCreation
4049
self.analytics = analytics
4150
self.accountService = accountService
4251
self.onPasswordUIRequest = onPasswordUIRequest
@@ -78,8 +87,16 @@ final class WPComEmailLoginViewModel: ObservableObject {
7887
}
7988
await startAuthentication(email: email, isPasswordlessAccount: passwordless)
8089
} catch {
81-
analytics.track(event: .JetpackSetup.loginFlow(step: .emailAddress, failure: error))
82-
onError(error.localizedDescription)
90+
guard allowAccountCreation,
91+
let apiError = error as? WordPressAPIError<WordPressComRestApiEndpointError>,
92+
case .endpointError(let endpointError) = apiError,
93+
endpointError.apiErrorCode == Constants.unknownUserErrorCode else {
94+
analytics.track(event: .JetpackSetup.loginFlow(step: .emailAddress, failure: error))
95+
onError(error.localizedDescription)
96+
return
97+
}
98+
99+
await requestAuthenticationLink(email: email, forAccountCreation: true)
83100
}
84101
}
85102

@@ -93,10 +110,13 @@ final class WPComEmailLoginViewModel: ObservableObject {
93110
}
94111

95112
@MainActor
96-
func requestAuthenticationLink(email: String) async {
113+
func requestAuthenticationLink(email: String, forAccountCreation: Bool = false) async {
97114
do {
98115
try await withCheckedThrowingContinuation { continuation in
99-
accountService.requestAuthenticationLink(for: email, jetpackLogin: false, success: {
116+
accountService.requestAuthenticationLink(for: email,
117+
jetpackLogin: false,
118+
createAccountIfNotFound: forAccountCreation,
119+
success: {
100120
continuation.resume()
101121
}, failure: { error in
102122
continuation.resume(throwing: error)
@@ -116,6 +136,7 @@ extension WPComEmailLoginViewModel {
116136
static let jetpackTermsURL = "https://jetpack.com/redirect/?source=wpcom-tos&site="
117137
static let jetpackShareDetailsURL = "https://jetpack.com/redirect/?source=jetpack-support-what-data-does-jetpack-sync&site="
118138
static let wpcomErrorCodeKey = "WordPressComRestApiErrorCodeKey"
139+
static let unknownUserErrorCode = "unknown_user"
119140
}
120141

121142
enum Localization {

WooCommerce/Classes/Authentication/WPComLogin/WPComLoginCoordinator.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,10 @@ private extension WPComLoginCoordinator {
151151
@MainActor
152152
func requestAuthenticationLink(email: String) async throws {
153153
try await withCheckedThrowingContinuation { continuation in
154-
accountService.requestAuthenticationLink(for: email, jetpackLogin: false, success: {
154+
accountService.requestAuthenticationLink(for: email,
155+
jetpackLogin: false,
156+
createAccountIfNotFound: false,
157+
success: {
155158
continuation.resume()
156159
}, failure: { error in
157160
continuation.resume(throwing: error)

WooCommerce/Classes/ViewRelated/JetpackSetup/JetpackSetupCoordinator.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import UIKit
2+
import Experiments
23
import Yosemite
34
import enum Networking.NetworkError
45
import class Networking.AlamofireNetwork
@@ -16,6 +17,7 @@ final class JetpackSetupCoordinator {
1617
private var jetpackConnectedEmail: String?
1718
private let stores: StoresManager
1819
private let analytics: Analytics
20+
private let featureFlagService: FeatureFlagService
1921
private let dotcomAuthScheme: String
2022

2123
private var loginNavigationController: LoginNavigationController?
@@ -24,6 +26,7 @@ final class JetpackSetupCoordinator {
2426
private lazy var emailLoginViewModel: WPComEmailLoginViewModel = {
2527
.init(siteURL: site.url,
2628
requiresConnectionOnly: requiresConnectionOnly,
29+
allowAccountCreation: featureFlagService.isFeatureFlagEnabled(.jetpackSetupWPComAccountCreation),
2730
onPasswordUIRequest: showPasswordUI(email:),
2831
onMagicLinkUIRequest: showMagicLinkUI(email:),
2932
onError: { [weak self] message in
@@ -40,13 +43,15 @@ final class JetpackSetupCoordinator {
4043
dotcomAuthScheme: String = ApiCredentials.dotcomAuthScheme,
4144
rootViewController: UIViewController,
4245
stores: StoresManager = ServiceLocator.stores,
43-
analytics: Analytics = ServiceLocator.analytics) {
46+
analytics: Analytics = ServiceLocator.analytics,
47+
featureFlagService: FeatureFlagService = ServiceLocator.featureFlagService) {
4448
self.site = site
4549
self.dotcomAuthScheme = dotcomAuthScheme
4650
self.requiresConnectionOnly = false // to be updated later after fetching Jetpack status
4751
self.rootViewController = rootViewController
4852
self.stores = stores
4953
self.analytics = analytics
54+
self.featureFlagService = featureFlagService
5055

5156
/// the authenticator needs to be initialized with configs
5257
/// to be used for requesting authentication link and handle login later.

WooCommerce/WooCommerceTests/Mocks/MockWordPressComAccountService.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,11 @@ final class MockWordPressComAccountService: WordPressComAccountServiceProtocol {
1717
failure(passwordlessAccountCheckError)
1818
}
1919

20-
func requestAuthenticationLink(for email: String, jetpackLogin: Bool, success: @escaping () -> Void, failure: @escaping (Error) -> Void) {
20+
func requestAuthenticationLink(for email: String,
21+
jetpackLogin: Bool,
22+
createAccountIfNotFound: Bool,
23+
success: @escaping () -> Void,
24+
failure: @escaping (Error) -> Void) {
2125
triggeredRequestAuthenticationLink = true
2226
guard let authenticationLinkRequestError else {
2327
return success()

0 commit comments

Comments
 (0)