Skip to content

Commit c25a94b

Browse files
committed
AccountRemote: add two new endpoints for JCP sites workaround.
1 parent a4200ec commit c25a94b

File tree

5 files changed

+142
-1
lines changed

5 files changed

+142
-1
lines changed

Networking/Networking.xcodeproj/project.pbxproj

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@
5252
02BA23CA22EEF62C009539E7 /* order-stats-v4-wcadmin-activated.json in Resources */ = {isa = PBXBuildFile; fileRef = 02BA23C822EEF62C009539E7 /* order-stats-v4-wcadmin-activated.json */; };
5353
02BDB83523EA98C800BCC63E /* String+HTML.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02BDB83423EA98C800BCC63E /* String+HTML.swift */; };
5454
02BDB83723EA9C4D00BCC63E /* String+HTMLTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02BDB83623EA9C4D00BCC63E /* String+HTMLTests.swift */; };
55+
02C11276274285FF00F4F0B4 /* WooCommerceAvailabilityMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02C11275274285FF00F4F0B4 /* WooCommerceAvailabilityMapper.swift */; };
56+
02C112782742862600F4F0B4 /* WordPressSiteSettingsMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02C112772742862600F4F0B4 /* WordPressSiteSettingsMapper.swift */; };
5557
02C1CEF424C6A02B00703EBA /* ProductVariationMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02C1CEF324C6A02B00703EBA /* ProductVariationMapper.swift */; };
5658
02C2548425635BD000A04423 /* ShippingLabelPaperSize.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02C2548325635BD000A04423 /* ShippingLabelPaperSize.swift */; };
5759
02C2549A25636E1500A04423 /* ShippingLabelAddress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02C2549925636E1500A04423 /* ShippingLabelAddress.swift */; };
@@ -630,6 +632,8 @@
630632
02BA23C822EEF62C009539E7 /* order-stats-v4-wcadmin-activated.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "order-stats-v4-wcadmin-activated.json"; sourceTree = "<group>"; };
631633
02BDB83423EA98C800BCC63E /* String+HTML.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+HTML.swift"; sourceTree = "<group>"; };
632634
02BDB83623EA9C4D00BCC63E /* String+HTMLTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+HTMLTests.swift"; sourceTree = "<group>"; };
635+
02C11275274285FF00F4F0B4 /* WooCommerceAvailabilityMapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WooCommerceAvailabilityMapper.swift; sourceTree = "<group>"; };
636+
02C112772742862600F4F0B4 /* WordPressSiteSettingsMapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WordPressSiteSettingsMapper.swift; sourceTree = "<group>"; };
633637
02C1CEF324C6A02B00703EBA /* ProductVariationMapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductVariationMapper.swift; sourceTree = "<group>"; };
634638
02C2548325635BD000A04423 /* ShippingLabelPaperSize.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShippingLabelPaperSize.swift; sourceTree = "<group>"; };
635639
02C2549925636E1500A04423 /* ShippingLabelAddress.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShippingLabelAddress.swift; sourceTree = "<group>"; };
@@ -1496,7 +1500,6 @@
14961500
029BA4EF255D7282006171FD /* ShippingLabelRemote.swift */,
14971501
D8EDFE1D25EE87F1003D2213 /* WCPayRemote.swift */,
14981502
FE28F6E5268429B6004465C7 /* UserRemote.swift */,
1499-
077F39D526A58E4500ABEADC /* SystemPluginsRemote.swift */,
15001503
077F39D526A58E4500ABEADC /* SystemStatusRemote.swift */,
15011504
AEF94584272974F2001DCCFB /* TelemetryRemote.swift */,
15021505
);
@@ -1844,6 +1847,8 @@
18441847
CC0786C4267BAF0F00BA9AC1 /* ShippingLabelStatusMapper.swift */,
18451848
FE28F6E326842848004465C7 /* UserMapper.swift */,
18461849
077F39D326A58DE700ABEADC /* SystemStatusMapper.swift */,
1850+
02C11275274285FF00F4F0B4 /* WooCommerceAvailabilityMapper.swift */,
1851+
02C112772742862600F4F0B4 /* WordPressSiteSettingsMapper.swift */,
18471852
);
18481853
path = Mapper;
18491854
sourceTree = "<group>";
@@ -2439,6 +2444,7 @@
24392444
743E84EC22171F4600FAC9D7 /* ShipmentTracking.swift in Sources */,
24402445
B56C1EB820EA76F500D749F9 /* Site.swift in Sources */,
24412446
26615473242D596B00A31661 /* ProductCategoriesRemote.swift in Sources */,
2447+
02C112782742862600F4F0B4 /* WordPressSiteSettingsMapper.swift in Sources */,
24422448
26615475242D7C9500A31661 /* ProductCategoryListMapper.swift in Sources */,
24432449
3178A49F2703E5CF00A8B4CA /* WCPayReaderLocationMapper.swift in Sources */,
24442450
45D685F823D0BC78005F87D0 /* ProductSkuMapper.swift in Sources */,
@@ -2517,6 +2523,7 @@
25172523
45152809257A7C6E0076B03C /* ProductAttributesRemote.swift in Sources */,
25182524
D8FBFF2222D5266E006E3336 /* OrderStatsV4Interval.swift in Sources */,
25192525
4568E2222459ADC60007E478 /* SitePostsRemote.swift in Sources */,
2526+
02C11276274285FF00F4F0B4 /* WooCommerceAvailabilityMapper.swift in Sources */,
25202527
CC0786C5267BAF0F00BA9AC1 /* ShippingLabelStatusMapper.swift in Sources */,
25212528
4515280D257A7EEC0076B03C /* ProductAttributeListMapper.swift in Sources */,
25222529
93D8BBFD226BBEE800AD2EB3 /* AccountSettingsMapper.swift in Sources */,
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import Foundation
2+
3+
/// Mapper: From WooCommerce site settings response to a boolean that indicates whether WooCommerce is active on the site
4+
///
5+
struct WooCommerceAvailabilityMapper: Mapper {
6+
7+
/// Any store with valid WooCommerce site settings response data is considered to have an active WooCommerce plugin.
8+
///
9+
func map(response: Data) throws -> Bool {
10+
true
11+
}
12+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import Foundation
2+
3+
/// Mapper: WordPress Site Settings
4+
///
5+
struct WordPressSiteSettingsMapper: Mapper {
6+
/// (Attempts) to convert a dictionary into `WordPressSiteSettings`.
7+
func map(response: Data) throws -> WordPressSiteSettings {
8+
let decoder = JSONDecoder()
9+
return try decoder.decode(WordPressSiteSettings.self, from: response)
10+
}
11+
}
12+
13+
/// Represents a WordPress Site Settings response.
14+
///
15+
public struct WordPressSiteSettings: Decodable, Equatable {
16+
/// Site's Name.
17+
public let name: String
18+
19+
/// Site's Description.
20+
public let description: String
21+
22+
/// Site's URL.
23+
public let url: String
24+
25+
private enum CodingKeys: String, CodingKey {
26+
case name = "title"
27+
case description
28+
case url
29+
}
30+
}

Networking/Networking/Remote/AccountRemote.swift

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,29 @@ public class AccountRemote: Remote {
6464
return enqueue(request, mapper: mapper)
6565
}
6666

67+
/// Checks the WooCommerce site settings endpoint to confirm if the WooCommerce plugin is available or not.
68+
/// We pass an empty `_fields` just to reduce the response payload size, as we don't care about the contents.
69+
/// The current use case is for a workaround for Jetpack Connection Package sites.
70+
/// - Parameter siteID: Site for which we will fetch the site settings.
71+
/// - Returns: A publisher that emits a boolean which indicates if WooCommerce plugin is active.
72+
public func checkIfWooCommerceIsActive(for siteID: Int64) -> AnyPublisher<Result<Bool, Error>, Never> {
73+
let parameters = ["_fields": ""]
74+
let request = JetpackRequest(wooApiVersion: .mark3, method: .get, siteID: siteID, path: Constants.wooCommerceSiteSettingsPath, parameters: parameters)
75+
let mapper = WooCommerceAvailabilityMapper()
76+
return enqueue(request, mapper: mapper)
77+
}
78+
79+
/// Fetches WordPress site settings for site metadata (e.g. name, description, URL).
80+
/// The current use case is for a workaround for Jetpack Connection Package sites.
81+
/// - Parameter siteID: Site for which we will fetch the site settings.
82+
/// - Returns: A publisher that emits the WordPress site settings.
83+
public func fetchWordPressSiteSettings(for siteID: Int64) -> AnyPublisher<Result<WordPressSiteSettings, Error>, Never> {
84+
let path = "sites/\(siteID)/settings"
85+
let request = DotcomRequest(wordpressApiVersion: .wpMark2, method: .get, path: path, parameters: nil)
86+
let mapper = WordPressSiteSettingsMapper()
87+
return enqueue(request, mapper: mapper)
88+
}
89+
6790
/// Loads the site plan for the default site associated with the WordPress.com user.
6891
///
6992
public func loadSitePlan(for siteID: Int64, completion: @escaping (Result<SitePlan, Error>) -> Void) {
@@ -78,3 +101,11 @@ public class AccountRemote: Remote {
78101
enqueue(request, mapper: mapper, completion: completion)
79102
}
80103
}
104+
105+
// MARK: - Constants
106+
//
107+
private extension AccountRemote {
108+
enum Constants {
109+
static let wooCommerceSiteSettingsPath: String = "settings"
110+
}
111+
}

Networking/NetworkingTests/Remote/AccountRemoteTests.swift

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,4 +81,65 @@ final class AccountRemoteTests: XCTestCase {
8181
XCTAssertEqual(jcpSites.count, 1)
8282
XCTAssertEqual(nonJCPSites.count, 1)
8383
}
84+
85+
// MARK: - `checkIfWooCommerceIsActive`
86+
87+
func test_checkIfWooCommerceIsActive_emits_true_when_response_is_valid() throws {
88+
// Given
89+
let siteID = Int64(277)
90+
let remote = AccountRemote(network: network)
91+
network.simulateResponse(requestUrlSuffix: "settings", filename: "wc-site-settings-partial")
92+
93+
// When
94+
let result = waitFor { promise in
95+
remote.checkIfWooCommerceIsActive(for: siteID).sink { result in
96+
promise(result)
97+
}.store(in: &self.cancellables)
98+
}
99+
100+
// Then
101+
XCTAssertTrue(result.isSuccess)
102+
let isWooCommerceActive = try XCTUnwrap(result.get())
103+
XCTAssertTrue(isWooCommerceActive)
104+
}
105+
106+
func test_checkIfWooCommerceIsActive_emits_false_when_error_is_returned() throws {
107+
// Given
108+
let siteID = Int64(277)
109+
let remote = AccountRemote(network: network)
110+
network.simulateError(requestUrlSuffix: "settings", error: NetworkError.notFound)
111+
112+
// When
113+
let result = waitFor { promise in
114+
remote.checkIfWooCommerceIsActive(for: siteID).sink { result in
115+
promise(result)
116+
}.store(in: &self.cancellables)
117+
}
118+
119+
// Then
120+
XCTAssertTrue(result.isFailure)
121+
let error = try XCTUnwrap(result.failure as? NetworkError)
122+
XCTAssertEqual(error, .notFound)
123+
}
124+
125+
// MARK: - `fetchWordPressSiteSettings`
126+
127+
func test_fetchWordPressSiteSettings_emits_settings_in_response() throws {
128+
// Given
129+
let siteID = Int64(277)
130+
let remote = AccountRemote(network: network)
131+
network.simulateResponse(requestUrlSuffix: "sites/\(siteID)/settings", filename: "wp-site-settings")
132+
133+
// When
134+
let result = waitFor { promise in
135+
remote.fetchWordPressSiteSettings(for: siteID).sink { result in
136+
promise(result)
137+
}.store(in: &self.cancellables)
138+
}
139+
140+
// Then
141+
XCTAssertTrue(result.isSuccess)
142+
let siteSettings = try XCTUnwrap(result.get())
143+
XCTAssertEqual(siteSettings.name, "Zucchini recipes")
144+
}
84145
}

0 commit comments

Comments
 (0)