Skip to content

Commit 6f20e78

Browse files
Merge pull request #114 from woocommerce/issue/93-stores-manager-improvements
StoresManager: API Improvements
2 parents 21f5559 + 81bf3a4 commit 6f20e78

File tree

7 files changed

+223
-122
lines changed

7 files changed

+223
-122
lines changed

WooCommerce/Classes/Authentication/AuthenticationManager.swift

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

154-
StoresManager.authenticate(username: username, authToken: authToken)
155-
156-
// TODO: Review
154+
StoresManager.shared.authenticate(username: username, authToken: authToken)
157155
onCompletion(nil)
158156
}
159157

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import Foundation
2+
import Yosemite
3+
import Storage
4+
import Networking
5+
6+
7+
8+
// MARK: - AuthenticatedState
9+
//
10+
class AuthenticatedState: StoresManagerState {
11+
12+
/// Active Credentials
13+
///
14+
private let credentials: Credentials
15+
16+
/// Dispatcher: Glues all of the Stores!
17+
///
18+
private let dispatcher = Dispatcher()
19+
20+
/// Retains all of the active Services
21+
///
22+
private let services: [ActionsProcessor]
23+
24+
/// CredentialsManager: By Reference, for unit testing purposes.
25+
///
26+
private let keychain: CredentialsManager
27+
28+
29+
30+
/// Designated Initializer
31+
///
32+
init(keychain: CredentialsManager, credentials: Credentials) {
33+
let storageManager = CoreDataManager.global
34+
let network = AlamofireNetwork(credentials: credentials)
35+
36+
services = [
37+
AccountStore(dispatcher: dispatcher, storageManager: storageManager, network: network)
38+
]
39+
40+
self.credentials = credentials
41+
self.keychain = keychain
42+
}
43+
44+
45+
/// Executed whenever the state is activated.
46+
///
47+
func didEnter() {
48+
keychain.saveDefaultCredentials(credentials)
49+
}
50+
51+
52+
/// Forwards the received action to the Actions Dispatcher.
53+
///
54+
func onAction(_ action: Action) {
55+
dispatcher.dispatch(action)
56+
}
57+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import Foundation
2+
import Yosemite
3+
4+
5+
6+
// MARK: - DeauthenticatedState
7+
//
8+
class DeauthenticatedState: StoresManagerState {
9+
10+
/// CredentialsManager: By Reference, for unit testing purposes.
11+
///
12+
private let keychain: CredentialsManager
13+
14+
15+
/// Designated Initializer
16+
///
17+
init(keychain: CredentialsManager) {
18+
self.keychain = keychain
19+
}
20+
21+
/// This method should run only when the app got deauthenticated.
22+
///
23+
func didEnter() {
24+
keychain.removeDefaultCredentials()
25+
AppDelegate.shared.displayAuthenticator()
26+
}
27+
28+
29+
/// NO-OP: During deauth method, we're not running any actions.
30+
///
31+
func onAction(_ action: Action) { }
32+
}

WooCommerce/Classes/Yosemite/StoresManager.swift

Lines changed: 36 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -9,39 +9,56 @@ import Networking
99
//
1010
class StoresManager {
1111

12-
/// Active (Internal) State
12+
/// Shared Instance
1313
///
14-
private static var state: StoresManagerState = initialState() {
14+
static var shared = StoresManager(keychain: .shared)
15+
16+
/// Active StoresManager State.
17+
///
18+
private var state: StoresManagerState {
1519
didSet {
1620
state.didEnter()
1721
}
1822
}
1923

24+
/// Credentials Manager: By Reference, for unit testing purposes.
25+
///
26+
private let keychain: CredentialsManager
2027

21-
/// This class is meant to be non (publicly) instantiable!
28+
/// Indicates if the StoresManager is currently authenticated, or not.
2229
///
23-
private init() { }
30+
var isAuthenticated: Bool {
31+
return state is AuthenticatedState
32+
}
2433

2534

35+
/// Designated Initializer
2636
///
27-
///
28-
class func authenticate(username: String, authToken: String) {
29-
let credentials = Credentials(username: username, authToken: authToken)
30-
state = state.authenticate(with: credentials)
37+
init(keychain: CredentialsManager) {
38+
self.state = StoresManager.initialState(from: keychain)
39+
self.keychain = keychain
3140
}
3241

3342

43+
/// Forwards the Action to the current State.
3444
///
45+
func dispatch(_ action: Action) {
46+
state.onAction(action)
47+
}
48+
49+
50+
/// Switches the internal state to Authenticated.
3551
///
36-
class func deauthenticate() {
37-
state = state.deauthenticate()
52+
func authenticate(username: String, authToken: String) {
53+
let credentials = Credentials(username: username, authToken: authToken)
54+
state = AuthenticatedState(keychain: keychain, credentials: credentials)
3855
}
3956

4057

41-
/// Forwards the Action to the current State.
58+
/// Switches the state to a Deauthenticated one.
4259
///
43-
class func dispatch(_ action: Action) {
44-
state.onAction(action)
60+
func deauthenticate() {
61+
state = DeauthenticatedState(keychain: keychain)
4562
}
4663
}
4764

@@ -52,124 +69,25 @@ private extension StoresManager {
5269

5370
/// Returns the Initial State, depending on whether we've got credentials or not.
5471
///
55-
class func initialState() -> StoresManagerState {
56-
guard let credentials = CredentialsManager.shared.loadDefaultCredentials() else {
57-
return DeauthenticatedState()
72+
class func initialState(from keychain: CredentialsManager) -> StoresManagerState {
73+
guard let credentials = keychain.loadDefaultCredentials() else {
74+
return DeauthenticatedState(keychain: keychain)
5875
}
5976

60-
return AuthenticatedState(credentials: credentials)
77+
return AuthenticatedState(keychain: keychain, credentials: credentials)
6178
}
6279
}
6380

6481

6582
// MARK: - StoresManagerState
6683
//
67-
private protocol StoresManagerState {
84+
protocol StoresManagerState {
6885

6986
/// Executed whenever the State is activated.
7087
///
7188
func didEnter()
7289

73-
/// Executed whenever an Action is received
90+
/// Executed whenever an Action is received.
7491
///
7592
func onAction(_ action: Action)
76-
77-
///
78-
///
79-
func deauthenticate() -> StoresManagerState
80-
81-
///
82-
///
83-
func authenticate(with credentials: Credentials) -> StoresManagerState
84-
}
85-
86-
87-
// MARK: - DeauthenticatedState
88-
//
89-
private class DeauthenticatedState: StoresManagerState {
90-
91-
/// This method should run only when the app got deauthenticated.
92-
///
93-
func didEnter() {
94-
CredentialsManager.shared.removeDefaultCredentials()
95-
AppDelegate.shared.displayAuthenticator()
96-
}
97-
98-
/// NO-OP: During deauth method, we're not running any actions.
99-
///
100-
func onAction(_ action: Action) { }
101-
102-
103-
/// Returns the next valid state, whenever there was a deauth event.
104-
///
105-
func deauthenticate() -> StoresManagerState {
106-
return self
107-
}
108-
109-
110-
/// Returns the next valid state, whenever there was an auth event.
111-
///
112-
func authenticate(with credentials: Credentials) -> StoresManagerState {
113-
return AuthenticatedState(credentials: credentials)
114-
}
115-
}
116-
117-
118-
// MARK: - AuthenticatedState
119-
//
120-
private class AuthenticatedState: StoresManagerState {
121-
122-
/// Active Credentials
123-
///
124-
private let credentials: Credentials
125-
126-
/// Dispatcher: Glues all of the Stores!
127-
///
128-
private let dispatcher = Dispatcher()
129-
130-
/// Retains all of the active Services
131-
///
132-
private let services: [ActionsProcessor]
133-
134-
135-
/// Designated Initializer
136-
///
137-
init(credentials: Credentials) {
138-
let storageManager = CoreDataManager.global
139-
let network = AlamofireNetwork(credentials: credentials)
140-
141-
services = [
142-
AccountStore(dispatcher: dispatcher, storageManager: storageManager, network: network)
143-
]
144-
145-
self.credentials = credentials
146-
}
147-
148-
149-
/// Executed whenever the state is activated.
150-
///
151-
func didEnter() {
152-
CredentialsManager.shared.saveDefaultCredentials(credentials)
153-
}
154-
155-
156-
/// Convenience Method: Forwards the received action to the active dispatcher.
157-
///
158-
func onAction(_ action: Action) {
159-
dispatcher.dispatch(action)
160-
}
161-
162-
163-
/// Returns the next valid state, whenever there was a deauth event.
164-
///
165-
func deauthenticate() -> StoresManagerState {
166-
return DeauthenticatedState()
167-
}
168-
169-
170-
/// Returns the next valid state, whenever there was an auth event.
171-
///
172-
func authenticate(with credentials: Credentials) -> StoresManagerState {
173-
return AuthenticatedState(credentials: credentials)
174-
}
17593
}

WooCommerce/WooCommerce.xcodeproj/project.pbxproj

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@
5757
B5D1AFB820BC510200DB0E8C /* UIImage+Woo.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D1AFB720BC510200DB0E8C /* UIImage+Woo.swift */; };
5858
B5D1AFBA20BC515600DB0E8C /* UIColor+Woo.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D1AFB920BC515600DB0E8C /* UIColor+Woo.swift */; };
5959
B5D1AFC020BC67C200DB0E8C /* WooConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D1AFBF20BC67C200DB0E8C /* WooConstants.swift */; };
60+
B5DBF3C320E1484400B53AED /* StoresManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5DBF3C220E1484400B53AED /* StoresManagerTests.swift */; };
61+
B5DBF3C520E148E000B53AED /* DeauthenticatedState.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5DBF3C420E148E000B53AED /* DeauthenticatedState.swift */; };
62+
B5DBF3CB20E149CC00B53AED /* AuthenticatedState.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5DBF3CA20E149CC00B53AED /* AuthenticatedState.swift */; };
6063
CE17C2E220ACA06800AFBD20 /* BillingDetailsTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE17C2E020ACA06800AFBD20 /* BillingDetailsTableViewCell.swift */; };
6164
CE17C2E320ACA06800AFBD20 /* BillingDetailsTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = CE17C2E120ACA06800AFBD20 /* BillingDetailsTableViewCell.xib */; };
6265
CE1CCB402056F21C000EE3AC /* Style.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE1CCB3F2056F21C000EE3AC /* Style.swift */; };
@@ -178,6 +181,9 @@
178181
B5D1AFB720BC510200DB0E8C /* UIImage+Woo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+Woo.swift"; sourceTree = "<group>"; };
179182
B5D1AFB920BC515600DB0E8C /* UIColor+Woo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIColor+Woo.swift"; sourceTree = "<group>"; };
180183
B5D1AFBF20BC67C200DB0E8C /* WooConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WooConstants.swift; sourceTree = "<group>"; };
184+
B5DBF3C220E1484400B53AED /* StoresManagerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoresManagerTests.swift; sourceTree = "<group>"; };
185+
B5DBF3C420E148E000B53AED /* DeauthenticatedState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeauthenticatedState.swift; sourceTree = "<group>"; };
186+
B5DBF3CA20E149CC00B53AED /* AuthenticatedState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthenticatedState.swift; sourceTree = "<group>"; };
181187
BABE5E07DD787ECA6D2A76DE /* Pods_WooCommerce.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_WooCommerce.framework; sourceTree = BUILT_PRODUCTS_DIR; };
182188
CE17C2E020ACA06800AFBD20 /* BillingDetailsTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BillingDetailsTableViewCell.swift; sourceTree = "<group>"; };
183189
CE17C2E120ACA06800AFBD20 /* BillingDetailsTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = BillingDetailsTableViewCell.xib; sourceTree = "<group>"; };
@@ -277,6 +283,8 @@
277283
isa = PBXGroup;
278284
children = (
279285
B53B898C20D462A000EDB467 /* StoresManager.swift */,
286+
B5DBF3CA20E149CC00B53AED /* AuthenticatedState.swift */,
287+
B5DBF3C420E148E000B53AED /* DeauthenticatedState.swift */,
280288
B54175F120D4C15D0083BB8C /* CoreDataManager+Woo.swift */,
281289
);
282290
path = Yosemite;
@@ -340,6 +348,7 @@
340348
isa = PBXGroup;
341349
children = (
342350
B53B898A20D4606400EDB467 /* System */,
351+
B5DBF3C120E1482900B53AED /* Yosemite */,
343352
B56DB3E32049BFAA00D4AA8E /* Info.plist */,
344353
);
345354
path = WooCommerceTests;
@@ -420,6 +429,14 @@
420429
path = System;
421430
sourceTree = "<group>";
422431
};
432+
B5DBF3C120E1482900B53AED /* Yosemite */ = {
433+
isa = PBXGroup;
434+
children = (
435+
B5DBF3C220E1484400B53AED /* StoresManagerTests.swift */,
436+
);
437+
path = Yosemite;
438+
sourceTree = "<group>";
439+
};
423440
CE1CCB3E2056F204000EE3AC /* Styles */ = {
424441
isa = PBXGroup;
425442
children = (
@@ -802,9 +819,11 @@
802819
B54175F220D4C15D0083BB8C /* CoreDataManager+Woo.swift in Sources */,
803820
B5A8F8AD20B88D9900D211DE /* LoginPrologueViewController.swift in Sources */,
804821
B5A8F8A920B84D3F00D211DE /* ApiCredentials.swift in Sources */,
822+
B5DBF3C520E148E000B53AED /* DeauthenticatedState.swift in Sources */,
805823
CE17C2E220ACA06800AFBD20 /* BillingDetailsTableViewCell.swift in Sources */,
806824
B55D4C2720B717C000D7A50F /* UserAgent.swift in Sources */,
807825
CE1CCB402056F21C000EE3AC /* Style.swift in Sources */,
826+
B5DBF3CB20E149CC00B53AED /* AuthenticatedState.swift in Sources */,
808827
CE1EC8F120B8A408009762BF /* OrderNoteTableViewCell.swift in Sources */,
809828
CE4DDB7B20DD312400D32EC8 /* Date+Helpers.swift in Sources */,
810829
B50911322049E27A007D25DC /* SettingsViewController.swift in Sources */,
@@ -846,6 +865,7 @@
846865
buildActionMask = 2147483647;
847866
files = (
848867
B53B898920D450AF00EDB467 /* CredentialsManagerTests.swift in Sources */,
868+
B5DBF3C320E1484400B53AED /* StoresManagerTests.swift in Sources */,
849869
);
850870
runOnlyForDeploymentPostprocessing = 0;
851871
};

WooCommerce/WooCommerceTests/System/CredentialsManagerTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ class CredentialsManagerTests: XCTestCase {
1212
private let manager = CredentialsManager(serviceName: Constants.testingServiceName)
1313

1414

15-
// MARK: - Overriden Methods
15+
// MARK: - Overridden Methods
1616

1717
override func setUp() {
1818
super.setUp()

0 commit comments

Comments
 (0)