Skip to content

Commit 5922f52

Browse files
authored
Merge pull request #5453 from woocommerce/feat/5364-jcp-workaround-endpoints
Jetpack CP: add 2 endpoints `wp/v2/settings` and `wc/v3/settings` for the workaround
2 parents 2d4ebb0 + feb94c9 commit 5922f52

File tree

7 files changed

+242
-1
lines changed

7 files changed

+242
-1
lines changed

Networking/Networking.xcodeproj/project.pbxproj

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,15 @@
4747
029BA4F0255D7282006171FD /* ShippingLabelRemote.swift in Sources */ = {isa = PBXBuildFile; fileRef = 029BA4EF255D7282006171FD /* ShippingLabelRemote.swift */; };
4848
029BA4F4255D72EC006171FD /* ShippingLabelPrintData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 029BA4F3255D72EC006171FD /* ShippingLabelPrintData.swift */; };
4949
029BA53B255DFABD006171FD /* ShippingLabelPrintDataMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 029BA53A255DFABD006171FD /* ShippingLabelPrintDataMapper.swift */; };
50+
02A26F1B2744F5FC008E4EDB /* wc-site-settings-partial.json in Resources */ = {isa = PBXBuildFile; fileRef = 02A26F192744F5FC008E4EDB /* wc-site-settings-partial.json */; };
51+
02A26F1C2744F5FC008E4EDB /* wp-site-settings.json in Resources */ = {isa = PBXBuildFile; fileRef = 02A26F1A2744F5FC008E4EDB /* wp-site-settings.json */; };
5052
02AAD53F250092A400BA1E26 /* product-add-or-delete.json in Resources */ = {isa = PBXBuildFile; fileRef = 02AAD53E250092A300BA1E26 /* product-add-or-delete.json */; };
5153
02BA23C922EEF62C009539E7 /* order-stats-v4-wcadmin-deactivated.json in Resources */ = {isa = PBXBuildFile; fileRef = 02BA23C722EEF62C009539E7 /* order-stats-v4-wcadmin-deactivated.json */; };
5254
02BA23CA22EEF62C009539E7 /* order-stats-v4-wcadmin-activated.json in Resources */ = {isa = PBXBuildFile; fileRef = 02BA23C822EEF62C009539E7 /* order-stats-v4-wcadmin-activated.json */; };
5355
02BDB83523EA98C800BCC63E /* String+HTML.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02BDB83423EA98C800BCC63E /* String+HTML.swift */; };
5456
02BDB83723EA9C4D00BCC63E /* String+HTMLTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02BDB83623EA9C4D00BCC63E /* String+HTMLTests.swift */; };
57+
02C11276274285FF00F4F0B4 /* WooCommerceAvailabilityMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02C11275274285FF00F4F0B4 /* WooCommerceAvailabilityMapper.swift */; };
58+
02C112782742862600F4F0B4 /* WordPressSiteSettingsMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02C112772742862600F4F0B4 /* WordPressSiteSettingsMapper.swift */; };
5559
02C1CEF424C6A02B00703EBA /* ProductVariationMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02C1CEF324C6A02B00703EBA /* ProductVariationMapper.swift */; };
5660
02C2548425635BD000A04423 /* ShippingLabelPaperSize.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02C2548325635BD000A04423 /* ShippingLabelPaperSize.swift */; };
5761
02C2549A25636E1500A04423 /* ShippingLabelAddress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02C2549925636E1500A04423 /* ShippingLabelAddress.swift */; };
@@ -625,11 +629,15 @@
625629
029BA4EF255D7282006171FD /* ShippingLabelRemote.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShippingLabelRemote.swift; sourceTree = "<group>"; };
626630
029BA4F3255D72EC006171FD /* ShippingLabelPrintData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShippingLabelPrintData.swift; sourceTree = "<group>"; };
627631
029BA53A255DFABD006171FD /* ShippingLabelPrintDataMapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShippingLabelPrintDataMapper.swift; sourceTree = "<group>"; };
632+
02A26F192744F5FC008E4EDB /* wc-site-settings-partial.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "wc-site-settings-partial.json"; sourceTree = "<group>"; };
633+
02A26F1A2744F5FC008E4EDB /* wp-site-settings.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "wp-site-settings.json"; sourceTree = "<group>"; };
628634
02AAD53E250092A300BA1E26 /* product-add-or-delete.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "product-add-or-delete.json"; sourceTree = "<group>"; };
629635
02BA23C722EEF62C009539E7 /* order-stats-v4-wcadmin-deactivated.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "order-stats-v4-wcadmin-deactivated.json"; sourceTree = "<group>"; };
630636
02BA23C822EEF62C009539E7 /* order-stats-v4-wcadmin-activated.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "order-stats-v4-wcadmin-activated.json"; sourceTree = "<group>"; };
631637
02BDB83423EA98C800BCC63E /* String+HTML.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+HTML.swift"; sourceTree = "<group>"; };
632638
02BDB83623EA9C4D00BCC63E /* String+HTMLTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+HTMLTests.swift"; sourceTree = "<group>"; };
639+
02C11275274285FF00F4F0B4 /* WooCommerceAvailabilityMapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WooCommerceAvailabilityMapper.swift; sourceTree = "<group>"; };
640+
02C112772742862600F4F0B4 /* WordPressSiteSettingsMapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WordPressSiteSettingsMapper.swift; sourceTree = "<group>"; };
633641
02C1CEF324C6A02B00703EBA /* ProductVariationMapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductVariationMapper.swift; sourceTree = "<group>"; };
634642
02C2548325635BD000A04423 /* ShippingLabelPaperSize.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShippingLabelPaperSize.swift; sourceTree = "<group>"; };
635643
02C2549925636E1500A04423 /* ShippingLabelAddress.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShippingLabelAddress.swift; sourceTree = "<group>"; };
@@ -1496,7 +1504,6 @@
14961504
029BA4EF255D7282006171FD /* ShippingLabelRemote.swift */,
14971505
D8EDFE1D25EE87F1003D2213 /* WCPayRemote.swift */,
14981506
FE28F6E5268429B6004465C7 /* UserRemote.swift */,
1499-
077F39D526A58E4500ABEADC /* SystemPluginsRemote.swift */,
15001507
077F39D526A58E4500ABEADC /* SystemStatusRemote.swift */,
15011508
AEF94584272974F2001DCCFB /* TelemetryRemote.swift */,
15021509
);
@@ -1737,6 +1744,7 @@
17371744
74ABA1C7213F19FE00FFAD30 /* top-performers-year.json */,
17381745
FE28F6E726842D57004465C7 /* user-complete.json */,
17391746
7495AACE225D366D00801A89 /* variation-as-product.json */,
1747+
02A26F192744F5FC008E4EDB /* wc-site-settings-partial.json */,
17401748
D800DA0D25EFEC21001E13CE /* wcpay-connection-token.json */,
17411749
318E8FD626C322EA00F519D7 /* wcpay-customer.json */,
17421750
318E8FD826C324D900F519D7 /* wcpay-customer-error.json */,
@@ -1767,6 +1775,7 @@
17671775
31B8D6B526583970008E3DB2 /* wcpay-account-implicitly-not-eligible.json */,
17681776
31799AFB2705189200D78179 /* wcpay-location.json */,
17691777
31799AFD270518AD00D78179 /* wcpay-location-error.json */,
1778+
02A26F1A2744F5FC008E4EDB /* wp-site-settings.json */,
17701779
077F39D726A58EB600ABEADC /* systemStatus.json */,
17711780
);
17721781
path = Responses;
@@ -1844,6 +1853,8 @@
18441853
CC0786C4267BAF0F00BA9AC1 /* ShippingLabelStatusMapper.swift */,
18451854
FE28F6E326842848004465C7 /* UserMapper.swift */,
18461855
077F39D326A58DE700ABEADC /* SystemStatusMapper.swift */,
1856+
02C11275274285FF00F4F0B4 /* WooCommerceAvailabilityMapper.swift */,
1857+
02C112772742862600F4F0B4 /* WordPressSiteSettingsMapper.swift */,
18471858
);
18481859
path = Mapper;
18491860
sourceTree = "<group>";
@@ -2147,6 +2158,7 @@
21472158
D88D5A43230BC668007B6E01 /* reviews-single.json in Resources */,
21482159
02DD6492248A3EC00082523E /* product-external.json in Resources */,
21492160
45A4B85C25D2FAB500776FB4 /* shipping-label-address-validation-error.json in Resources */,
2161+
02A26F1C2744F5FC008E4EDB /* wp-site-settings.json in Resources */,
21502162
740211DF2193985A002248DA /* comment-moderate-spam.json in Resources */,
21512163
B5147876211B9227007562E5 /* broken-orders-mark-2.json in Resources */,
21522164
3158FE6C26129D2E00E566B9 /* wcpay-account-rejected-terms-of-service.json in Resources */,
@@ -2157,6 +2169,7 @@
21572169
CE50346721B5DCBE007573C6 /* site-plan.json in Resources */,
21582170
743E84F322172D0A00FAC9D7 /* shipment_tracking_empty.json in Resources */,
21592171
B505F6D520BEE4E700BB1B69 /* me.json in Resources */,
2172+
02A26F1B2744F5FC008E4EDB /* wc-site-settings-partial.json in Resources */,
21602173
028FA474257E110700F88A48 /* shipping-label-refund-success.json in Resources */,
21612174
02BA23C922EEF62C009539E7 /* order-stats-v4-wcadmin-deactivated.json in Resources */,
21622175
CCB2CAA226209A1200285CA0 /* generic_success_data.json in Resources */,
@@ -2439,6 +2452,7 @@
24392452
743E84EC22171F4600FAC9D7 /* ShipmentTracking.swift in Sources */,
24402453
B56C1EB820EA76F500D749F9 /* Site.swift in Sources */,
24412454
26615473242D596B00A31661 /* ProductCategoriesRemote.swift in Sources */,
2455+
02C112782742862600F4F0B4 /* WordPressSiteSettingsMapper.swift in Sources */,
24422456
26615475242D7C9500A31661 /* ProductCategoryListMapper.swift in Sources */,
24432457
3178A49F2703E5CF00A8B4CA /* WCPayReaderLocationMapper.swift in Sources */,
24442458
45D685F823D0BC78005F87D0 /* ProductSkuMapper.swift in Sources */,
@@ -2517,6 +2531,7 @@
25172531
45152809257A7C6E0076B03C /* ProductAttributesRemote.swift in Sources */,
25182532
D8FBFF2222D5266E006E3336 /* OrderStatsV4Interval.swift in Sources */,
25192533
4568E2222459ADC60007E478 /* SitePostsRemote.swift in Sources */,
2534+
02C11276274285FF00F4F0B4 /* WooCommerceAvailabilityMapper.swift in Sources */,
25202535
CC0786C5267BAF0F00BA9AC1 /* ShippingLabelStatusMapper.swift in Sources */,
25212536
4515280D257A7EEC0076B03C /* ProductAttributeListMapper.swift in Sources */,
25222537
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
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
{
2+
"data": [
3+
{
4+
"id": "wc_admin",
5+
"label": "WooCommerce Admin",
6+
"description": "Settings for WooCommerce admin reporting.",
7+
"parent_id": "",
8+
"sub_groups": [],
9+
"_links": {
10+
"options": [
11+
{
12+
"href": "https://toma.to/wp-json/wc/v3/settings/wc_admin"
13+
}
14+
]
15+
}
16+
},
17+
{
18+
"id": "general",
19+
"label": "General",
20+
"description": "",
21+
"parent_id": "",
22+
"sub_groups": [],
23+
"_links": {
24+
"options": [
25+
{
26+
"href": "https://toma.to/wp-json/wc/v3/settings/general"
27+
}
28+
]
29+
}
30+
},
31+
{
32+
"id": "products",
33+
"label": "Products",
34+
"description": "",
35+
"parent_id": "",
36+
"sub_groups": [],
37+
"_links": {
38+
"options": [
39+
{
40+
"href": "https://toma.to/wp-json/wc/v3/settings/products"
41+
}
42+
]
43+
}
44+
},
45+
{
46+
"id": "shipping",
47+
"label": "Shipping",
48+
"description": "",
49+
"parent_id": "",
50+
"sub_groups": [],
51+
"_links": {
52+
"options": [
53+
{
54+
"href": "https://toma.to/wp-json/wc/v3/settings/shipping"
55+
}
56+
]
57+
}
58+
},
59+
{
60+
"id": "account",
61+
"label": "Accounts &amp; Privacy",
62+
"description": "",
63+
"parent_id": "",
64+
"sub_groups": [],
65+
"_links": {
66+
"options": [
67+
{
68+
"href": "https://toma.to/wp-json/wc/v3/settings/account"
69+
}
70+
]
71+
}
72+
}
73+
]
74+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"title": "Zucchini recipes",
3+
"description": "All things zucchini and more",
4+
"url": "https://zucchini.mystagingwebsite.com",
5+
"email": "[email protected]",
6+
"timezone": "America/New_York",
7+
"date_format": "F j, Y",
8+
"time_format": "H:i",
9+
"start_of_week": 1,
10+
"language": "",
11+
"use_smilies": true,
12+
"default_category": 1,
13+
"default_post_format": "0",
14+
"posts_per_page": 10,
15+
"default_ping_status": "open",
16+
"default_comment_status": "open",
17+
"site_logo": null
18+
}

0 commit comments

Comments
 (0)