Skip to content

Commit e87fa79

Browse files
Merge pull request #143 from woocommerce/issue/90-session-stores-account
SessionManager: Keeping a reference to Account!
2 parents f1c953e + f810e3e commit e87fa79

File tree

11 files changed

+135
-44
lines changed

11 files changed

+135
-44
lines changed

WooCommerce/Classes/AppDelegate.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
3131

3232

3333

34+
// MARK: - AppDelegate Methods
35+
3436
func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]? = nil) -> Bool {
3537

3638
// Setup the Interface!
@@ -44,6 +46,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
4446
// Display the Authentication UI
4547
displayAuthenticatorIfNeeded()
4648

49+
// Yosemite Initialization
50+
synchronizeEntitiesIfPossible()
51+
4752
return true
4853
}
4954

@@ -181,4 +186,14 @@ extension AppDelegate {
181186

182187
authenticationManager.displayAuthentication(from: rootViewController)
183188
}
189+
190+
/// Whenever we're in an Authenticated state, let's Sync all of the WC-Y entities.
191+
///
192+
func synchronizeEntitiesIfPossible() {
193+
guard StoresManager.shared.isAuthenticated else {
194+
return
195+
}
196+
197+
StoresManager.shared.synchronizeEntities()
198+
}
184199
}

WooCommerce/Classes/Authentication/AuthenticationManager.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,8 +151,9 @@ extension AuthenticationManager: WordPressAuthenticatorDelegate {
151151
fatalError("Self Hosted sites are not supported. Please review the Authenticator settings!")
152152
}
153153

154-
StoresManager.shared.authenticate(username: username, authToken: authToken)
155-
onCompletion(nil)
154+
StoresManager.shared
155+
.authenticate(credentials: .init(username: username, authToken: authToken))
156+
.synchronizeEntities(onCompletion: onCompletion)
156157
}
157158

158159
/// Tracks a given Analytics Event.

WooCommerce/Classes/Extensions/UserDefaults+Woo.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import Foundation
66
//
77
extension UserDefaults {
88
enum Key: String {
9+
case defaultAccountID
910
case defaultUsername
1011
case defaultStoreID
1112
}

WooCommerce/Classes/System/SessionManager.swift

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,17 @@ struct SessionManager {
2222
///
2323
private let keychain: Keychain
2424

25-
/// Active Credentials.
25+
/// Default Credentials.
2626
///
27-
var credentials: Credentials? {
27+
var defaultCredentials: Credentials? {
2828
get {
2929
return loadCredentials()
3030
}
3131
set {
32+
guard newValue != defaultCredentials else {
33+
return
34+
}
35+
3236
guard let credentials = newValue else {
3337
removeCredentials()
3438
return
@@ -38,14 +42,28 @@ struct SessionManager {
3842
}
3943
}
4044

41-
/// Active Store's Site ID.
45+
/// Ephemeral: Default Account.
46+
///
47+
var defaultAccount: Yosemite.Account? {
48+
didSet {
49+
defaults[.defaultAccountID] = defaultAccount?.userID
50+
}
51+
}
52+
53+
/// Default AccountID: Returns the last known Account's User ID.
54+
///
55+
var defaultAccountID: Int? {
56+
return defaults[.defaultAccountID]
57+
}
58+
59+
/// Default StoreID.
4260
///
43-
var storeID: Int? {
61+
var defaultStoreID: Int? {
4462
get {
4563
return defaults[.defaultStoreID]
4664
}
4765
set {
48-
defaults[.defaultStoreID] = storeID
66+
defaults[.defaultStoreID] = defaultStoreID
4967
}
5068
}
5169

@@ -60,8 +78,9 @@ struct SessionManager {
6078
/// Nukes all of the known Session's properties.
6179
///
6280
mutating func reset() {
63-
credentials = nil
64-
storeID = nil
81+
defaultAccount = nil
82+
defaultCredentials = nil
83+
defaultStoreID = nil
6584
}
6685
}
6786

WooCommerce/Classes/Yosemite/AuthenticatedState.swift

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,6 @@ import Networking
99
//
1010
class AuthenticatedState: StoresManagerState {
1111

12-
/// Active Credentials
13-
///
14-
private let credentials: Credentials
15-
1612
/// Dispatcher: Glues all of the Stores!
1713
///
1814
private let dispatcher = Dispatcher()
@@ -33,8 +29,16 @@ class AuthenticatedState: StoresManagerState {
3329
OrderStore(dispatcher: dispatcher, storageManager: storageManager, network: network),
3430
OrderNoteStore(dispatcher: dispatcher, storageManager: storageManager, network: network)
3531
]
32+
}
33+
34+
/// Convenience Initializer
35+
///
36+
convenience init?(sessionManager: SessionManager) {
37+
guard let credentials = sessionManager.defaultCredentials else {
38+
return nil
39+
}
3640

37-
self.credentials = credentials
41+
self.init(credentials: credentials)
3842
}
3943

4044

WooCommerce/Classes/Yosemite/DeauthenticatedState.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ class DeauthenticatedState: StoresManagerState {
1313
AppDelegate.shared.displayAuthenticator()
1414
}
1515

16-
1716
/// NO-OP: During deauth method, we're not running any actions.
1817
///
1918
func onAction(_ action: Action) { }

WooCommerce/Classes/Yosemite/StoresManager.swift

Lines changed: 55 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ class StoresManager {
1717

1818
/// Active StoresManager State.
1919
///
20-
private var state: StoresManagerState = DeauthenticatedState() {
20+
private var state: StoresManagerState {
2121
didSet {
2222
state.didEnter()
2323
}
@@ -30,11 +30,14 @@ class StoresManager {
3030
}
3131

3232

33+
3334
/// Designated Initializer
3435
///
3536
init(sessionManager: SessionManager) {
3637
self.sessionManager = sessionManager
37-
authenticateIfPossible()
38+
self.state = AuthenticatedState(sessionManager: sessionManager) ?? DeauthenticatedState()
39+
40+
restoreSessionAccountIfPossible()
3841
}
3942

4043

@@ -44,38 +47,77 @@ class StoresManager {
4447
state.onAction(action)
4548
}
4649

47-
4850
/// Switches the internal state to Authenticated.
4951
///
50-
func authenticate(username: String, authToken: String) {
51-
let credentials = Credentials(username: username, authToken: authToken)
52-
52+
@discardableResult
53+
func authenticate(credentials: Credentials) -> StoresManager {
5354
state = AuthenticatedState(credentials: credentials)
54-
sessionManager.credentials = credentials
55+
sessionManager.defaultCredentials = credentials
56+
57+
return self
5558
}
5659

60+
/// Synchronizes all of the Session's Entities.
61+
///
62+
@discardableResult
63+
func synchronizeEntities(onCompletion: ((Error?) -> Void)? = nil) -> StoresManager {
64+
synchronizeAccount(onCompletion: onCompletion)
65+
66+
return self
67+
}
5768

5869
/// Switches the state to a Deauthenticated one.
5970
///
60-
func deauthenticate() {
71+
@discardableResult
72+
func deauthenticate() -> StoresManager {
6173
state = DeauthenticatedState()
6274
sessionManager.reset()
75+
76+
return self
6377
}
6478
}
6579

6680

67-
// MARK: - StoresManager Private Methods
81+
// MARK: - Private Methods
6882
//
6983
private extension StoresManager {
7084

71-
/// Switches over to the AuthenticatedState whenever needed / possible!.
85+
/// Loads the Default Account into the current Session, if possible.
7286
///
73-
func authenticateIfPossible() {
74-
guard let credentials = sessionManager.credentials else {
87+
func restoreSessionAccountIfPossible() {
88+
guard let accountID = sessionManager.defaultAccountID else {
7589
return
7690
}
7791

78-
state = AuthenticatedState(credentials: credentials)
92+
restoreSessionAccount(with: accountID)
93+
}
94+
95+
/// Loads the specified accountID into the Session, if possible.
96+
///
97+
func restoreSessionAccount(with accountID: Int) {
98+
let action = AccountAction.loadAccount(userID: accountID) { [weak self] account in
99+
guard let `self` = self, let account = account else {
100+
return
101+
}
102+
103+
self.sessionManager.defaultAccount = account
104+
}
105+
106+
dispatch(action)
107+
}
108+
109+
/// Synchronizes the WordPress.com Account, associated with the current credentials.
110+
///
111+
func synchronizeAccount(onCompletion: ((Error?) -> Void)?) {
112+
let action = AccountAction.synchronizeAccount { [weak self] (account, error) in
113+
if let `self` = self, let account = account, self.isAuthenticated {
114+
self.sessionManager.defaultAccount = account
115+
}
116+
117+
onCompletion?(error)
118+
}
119+
120+
dispatch(action)
79121
}
80122
}
81123

WooCommerce/WooCommerceTests/System/SessionManagerTests.swift

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,23 +16,23 @@ class SessionManagerTests: XCTestCase {
1616

1717
override func setUp() {
1818
super.setUp()
19-
manager.credentials = nil
19+
manager.defaultCredentials = nil
2020
}
2121

2222

2323
/// Verifies that `loadDefaultCredentials` returns nil whenever there are no default credentials stored.
2424
///
2525
func testLoadDefaultCredentialsReturnsNilWhenThereAreNoDefaultCredentials() {
26-
XCTAssertNil(manager.credentials)
26+
XCTAssertNil(manager.defaultCredentials)
2727
}
2828

2929

3030
/// Verifies that `loadDefaultCredentials` effectively returns the last stored credentials
3131
///
3232
func testDefaultCredentialsAreProperlyPersisted() {
33-
manager.credentials = Settings.credentials1
33+
manager.defaultCredentials = Settings.credentials1
3434

35-
let retrieved = manager.credentials
35+
let retrieved = manager.defaultCredentials
3636
XCTAssertEqual(retrieved?.authToken, Settings.credentials1.authToken)
3737
XCTAssertEqual(retrieved?.username, Settings.credentials1.username)
3838
}
@@ -41,21 +41,21 @@ class SessionManagerTests: XCTestCase {
4141
/// Verifies that `removeDefaultCredentials` effectively nukes everything from the keychain
4242
///
4343
func testDefaultCredentialsAreEffectivelyNuked() {
44-
manager.credentials = Settings.credentials1
45-
manager.credentials = nil
44+
manager.defaultCredentials = Settings.credentials1
45+
manager.defaultCredentials = nil
4646

47-
XCTAssertNil(manager.credentials)
47+
XCTAssertNil(manager.defaultCredentials)
4848
}
4949

5050

5151
/// Verifies that `saveDefaultCredentials` overrides previous stored credentials
5252
///
5353
func testDefaultCredentialsCanBeUpdated() {
54-
manager.credentials = Settings.credentials1
55-
XCTAssertEqual(manager.credentials, Settings.credentials1)
54+
manager.defaultCredentials = Settings.credentials1
55+
XCTAssertEqual(manager.defaultCredentials, Settings.credentials1)
5656

57-
manager.credentials = Settings.credentials2
58-
XCTAssertEqual(manager.credentials, Settings.credentials2)
57+
manager.defaultCredentials = Settings.credentials2
58+
XCTAssertEqual(manager.defaultCredentials, Settings.credentials2)
5959
}
6060
}
6161

WooCommerce/WooCommerceTests/Yosemite/StoresManagerTests.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ class StoresManagerTests: XCTestCase {
2828
///
2929
func testInitialStateIsAuthenticatedAssumingCredentialsWereNotMissing() {
3030
var session = SessionManager.testingInstance
31-
session.credentials = Settings.credentials
31+
session.defaultCredentials = Settings.credentials
3232

3333
let manager = StoresManager.testingInstance
3434
XCTAssertTrue(manager.isAuthenticated)
@@ -39,7 +39,7 @@ class StoresManagerTests: XCTestCase {
3939
///
4040
func testAuthenticateEffectivelyTogglesStoreManagerToAuthenticatedState() {
4141
let manager = StoresManager.testingInstance
42-
manager.authenticate(username: Settings.credentials.username, authToken: Settings.credentials.authToken)
42+
manager.authenticate(credentials: Settings.credentials)
4343

4444
XCTAssertTrue(manager.isAuthenticated)
4545
}
@@ -49,7 +49,7 @@ class StoresManagerTests: XCTestCase {
4949
///
5050
func testDeauthenticateEffectivelyTogglesStoreManagerToDeauthenticatedState() {
5151
let manager = StoresManager.testingInstance
52-
manager.authenticate(username: Settings.credentials.username, authToken: Settings.credentials.authToken)
52+
manager.authenticate(credentials: Settings.credentials)
5353
manager.deauthenticate()
5454

5555
XCTAssertFalse(manager.isAuthenticated)
@@ -60,10 +60,10 @@ class StoresManagerTests: XCTestCase {
6060
///
6161
func testAuthenticatePersistsDefaultCredentialsInKeychain() {
6262
let manager = StoresManager.testingInstance
63-
manager.authenticate(username: Settings.credentials.username, authToken: Settings.credentials.authToken)
63+
manager.authenticate(credentials: Settings.credentials)
6464

6565
let session = SessionManager.testingInstance
66-
XCTAssertEqual(session.credentials, Settings.credentials)
66+
XCTAssertEqual(session.defaultCredentials, Settings.credentials)
6767
}
6868
}
6969

Yosemite/Yosemite/Actions/AccountAction.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@ import Networking
77
//
88
public enum AccountAction: Action {
99
case synchronizeAccount(onCompletion: (Account?, Error?) -> Void)
10+
case loadAccount(userID: Int, onCompletion: (Account?) -> Void)
1011
}

0 commit comments

Comments
 (0)