Skip to content

Commit

Permalink
Merge pull request #576 from wordpress-mobile/feature/jetpack-proxy-r…
Browse files Browse the repository at this point in the history
…emote

Add Jetpack Proxy remote service
  • Loading branch information
dvdchr authored Feb 10, 2023
2 parents 1aa3671 + 4e60447 commit 2c2b4c3
Show file tree
Hide file tree
Showing 4 changed files with 195 additions and 7 deletions.
2 changes: 1 addition & 1 deletion WordPressKit.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Pod::Spec.new do |s|
s.name = 'WordPressKit'
s.version = '6.0.0'
s.version = '6.1.0-beta.1'

s.summary = 'WordPressKit offers a clean and simple WordPress.com and WordPress.org API.'
s.description = <<-DESC
Expand Down
20 changes: 14 additions & 6 deletions WordPressKit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -124,14 +124,14 @@
46ABD0EA262EEE0400C7FF24 /* AppTransportSecuritySettingsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46ABD0E9262EEE0400C7FF24 /* AppTransportSecuritySettingsTests.swift */; };
4A1DEF44293051BC00322608 /* LoggingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A1DEF43293051BC00322608 /* LoggingTests.swift */; };
4A1DEF46293051C600322608 /* LoggingTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4A1DEF45293051C600322608 /* LoggingTests.m */; };
4A68E3DD294070A7004AC3DC /* RemoteReaderSite.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A68E3DC294070A7004AC3DC /* RemoteReaderSite.swift */; };
4A68E3DF29407100004AC3DC /* RemoteReaderTopic.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A68E3DE29407100004AC3DC /* RemoteReaderTopic.swift */; };
4A68E3E1294076C1004AC3DC /* RemoteReaderSiteInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A68E3E0294076C1004AC3DC /* RemoteReaderSiteInfo.swift */; };
4A68E3CD29404181004AC3DC /* RemoteBlog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A68E3CC29404181004AC3DC /* RemoteBlog.swift */; };
4A68E3CF29404289004AC3DC /* RemoteBlogOptionsHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A68E3CE29404289004AC3DC /* RemoteBlogOptionsHelper.swift */; };
4A68E3D329406AA0004AC3DC /* RemoteMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A68E3D029406AA0004AC3DC /* RemoteMenu.swift */; };
4A68E3D429406AA0004AC3DC /* RemoteMenuItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A68E3D129406AA0004AC3DC /* RemoteMenuItem.swift */; };
4A68E3D529406AA0004AC3DC /* RemoteMenuLocation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A68E3D229406AA0004AC3DC /* RemoteMenuLocation.swift */; };
4A68E3DD294070A7004AC3DC /* RemoteReaderSite.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A68E3DC294070A7004AC3DC /* RemoteReaderSite.swift */; };
4A68E3DF29407100004AC3DC /* RemoteReaderTopic.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A68E3DE29407100004AC3DC /* RemoteReaderTopic.swift */; };
4A68E3E1294076C1004AC3DC /* RemoteReaderSiteInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A68E3E0294076C1004AC3DC /* RemoteReaderSiteInfo.swift */; };
57BCD3D426209D9500292CB3 /* AppTransportSecuritySettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57BCD3D326209D9500292CB3 /* AppTransportSecuritySettings.swift */; };
730E869F21E44EFD00753E1A /* WordPressComServiceRemote+SiteVerticals.swift in Sources */ = {isa = PBXBuildFile; fileRef = 730E869E21E44EFD00753E1A /* WordPressComServiceRemote+SiteVerticals.swift */; };
731BA83621DECD61000FDFCD /* SiteCreationRequestEncodingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 731BA83521DECD61000FDFCD /* SiteCreationRequestEncodingTests.swift */; };
Expand Down Expand Up @@ -613,7 +613,9 @@
FE20A6A6282BC68D0025E975 /* blogging-prompts-settings-fetch-success.json in Resources */ = {isa = PBXBuildFile; fileRef = FE20A6A5282BC68D0025E975 /* blogging-prompts-settings-fetch-success.json */; };
FE20A6A8282BC83A0025E975 /* blogging-prompts-settings-update-with-response.json in Resources */ = {isa = PBXBuildFile; fileRef = FE20A6A7282BC83A0025E975 /* blogging-prompts-settings-update-with-response.json */; };
FE20A6AA282BC8710025E975 /* blogging-prompts-settings-update-empty-response.json in Resources */ = {isa = PBXBuildFile; fileRef = FE20A6A9282BC8710025E975 /* blogging-prompts-settings-update-empty-response.json */; };
FEAE3AC7298AC2A300E05A24 /* JetpackProxyServiceRemote.swift in Sources */ = {isa = PBXBuildFile; fileRef = FEAE3AC6298AC2A300E05A24 /* JetpackProxyServiceRemote.swift */; };
FEB7A88F271873BD00A8CF85 /* reader-post-comments-update-notification-success.json in Resources */ = {isa = PBXBuildFile; fileRef = FEB7A88E271873BD00A8CF85 /* reader-post-comments-update-notification-success.json */; };
FED77253298B819900C2346E /* JetpackProxyServiceRemoteTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FED77252298B819900C2346E /* JetpackProxyServiceRemoteTests.swift */; };
FEE4EF57272FDD4B003CDA3C /* RemoteCommentV2.swift in Sources */ = {isa = PBXBuildFile; fileRef = FEE4EF56272FDD4B003CDA3C /* RemoteCommentV2.swift */; };
FEE4EF59272FF78C003CDA3C /* CommentServiceRemoteREST+ApiV2.swift in Sources */ = {isa = PBXBuildFile; fileRef = FEE4EF58272FF78C003CDA3C /* CommentServiceRemoteREST+ApiV2.swift */; };
FEE4EF5B27302317003CDA3C /* CommentServiceRemoteREST+APIv2Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FEE4EF5A27302317003CDA3C /* CommentServiceRemoteREST+APIv2Tests.swift */; };
Expand Down Expand Up @@ -778,14 +780,14 @@
46ABD0E9262EEE0400C7FF24 /* AppTransportSecuritySettingsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppTransportSecuritySettingsTests.swift; sourceTree = "<group>"; };
4A1DEF43293051BC00322608 /* LoggingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoggingTests.swift; sourceTree = "<group>"; };
4A1DEF45293051C600322608 /* LoggingTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LoggingTests.m; sourceTree = "<group>"; };
4A68E3DC294070A7004AC3DC /* RemoteReaderSite.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemoteReaderSite.swift; sourceTree = "<group>"; };
4A68E3DE29407100004AC3DC /* RemoteReaderTopic.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemoteReaderTopic.swift; sourceTree = "<group>"; };
4A68E3E0294076C1004AC3DC /* RemoteReaderSiteInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemoteReaderSiteInfo.swift; sourceTree = "<group>"; };
4A68E3CC29404181004AC3DC /* RemoteBlog.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemoteBlog.swift; sourceTree = "<group>"; };
4A68E3CE29404289004AC3DC /* RemoteBlogOptionsHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemoteBlogOptionsHelper.swift; sourceTree = "<group>"; };
4A68E3D029406AA0004AC3DC /* RemoteMenu.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemoteMenu.swift; sourceTree = "<group>"; };
4A68E3D129406AA0004AC3DC /* RemoteMenuItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemoteMenuItem.swift; sourceTree = "<group>"; };
4A68E3D229406AA0004AC3DC /* RemoteMenuLocation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemoteMenuLocation.swift; sourceTree = "<group>"; };
4A68E3DC294070A7004AC3DC /* RemoteReaderSite.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemoteReaderSite.swift; sourceTree = "<group>"; };
4A68E3DE29407100004AC3DC /* RemoteReaderTopic.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemoteReaderTopic.swift; sourceTree = "<group>"; };
4A68E3E0294076C1004AC3DC /* RemoteReaderSiteInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemoteReaderSiteInfo.swift; sourceTree = "<group>"; };
57BCD3D326209D9500292CB3 /* AppTransportSecuritySettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppTransportSecuritySettings.swift; sourceTree = "<group>"; };
6C2A33D76FD1052D6F30466D /* Pods-WordPressKit.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WordPressKit.debug.xcconfig"; path = "Pods/Target Support Files/Pods-WordPressKit/Pods-WordPressKit.debug.xcconfig"; sourceTree = "<group>"; };
6F2E0CC4FA01B5475A378DA2 /* Pods-WordPressKitTests.release-alpha.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WordPressKitTests.release-alpha.xcconfig"; path = "Pods/Target Support Files/Pods-WordPressKitTests/Pods-WordPressKitTests.release-alpha.xcconfig"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1278,7 +1280,9 @@
FE20A6A5282BC68D0025E975 /* blogging-prompts-settings-fetch-success.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "blogging-prompts-settings-fetch-success.json"; sourceTree = "<group>"; };
FE20A6A7282BC83A0025E975 /* blogging-prompts-settings-update-with-response.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "blogging-prompts-settings-update-with-response.json"; sourceTree = "<group>"; };
FE20A6A9282BC8710025E975 /* blogging-prompts-settings-update-empty-response.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "blogging-prompts-settings-update-empty-response.json"; sourceTree = "<group>"; };
FEAE3AC6298AC2A300E05A24 /* JetpackProxyServiceRemote.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JetpackProxyServiceRemote.swift; sourceTree = "<group>"; };
FEB7A88E271873BD00A8CF85 /* reader-post-comments-update-notification-success.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "reader-post-comments-update-notification-success.json"; sourceTree = "<group>"; };
FED77252298B819900C2346E /* JetpackProxyServiceRemoteTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JetpackProxyServiceRemoteTests.swift; sourceTree = "<group>"; };
FEE4EF56272FDD4B003CDA3C /* RemoteCommentV2.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteCommentV2.swift; sourceTree = "<group>"; };
FEE4EF58272FF78C003CDA3C /* CommentServiceRemoteREST+ApiV2.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CommentServiceRemoteREST+ApiV2.swift"; sourceTree = "<group>"; };
FEE4EF5A27302317003CDA3C /* CommentServiceRemoteREST+APIv2Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CommentServiceRemoteREST+APIv2Tests.swift"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1822,6 +1826,7 @@
8B749DEC25AF3E4600023F03 /* JetpackCapabilitiesServiceRemote.swift */,
32FC1D27255C91ED00CD0A7B /* JetpackScanServiceRemote.swift */,
9A2D0B27225E0119009E585F /* JetpackServiceRemote.swift */,
FEAE3AC6298AC2A300E05A24 /* JetpackProxyServiceRemote.swift */,
439A44D52107C66A00795ED7 /* JSONDecoderExtension.swift */,
74DA56361F06EB0500FE9BF4 /* MediaServiceRemote.h */,
74DA562E1F06EAF000FE9BF4 /* MediaServiceRemoteREST.h */,
Expand Down Expand Up @@ -2330,6 +2335,7 @@
3297E1DC2564649D00287D21 /* Scan */,
9A2D0B2A225E0E22009E585F /* JetpackServiceRemoteTests.swift */,
8B749E8125AF7DDA00023F03 /* JetpackCapabilitiesServiceRemoteTests.swift */,
FED77252298B819900C2346E /* JetpackProxyServiceRemoteTests.swift */,
);
name = Jetpack;
sourceTree = "<group>";
Expand Down Expand Up @@ -3027,6 +3033,7 @@
464BAB0B262F6736006AEED5 /* RemoteBlockEditorSettings.swift in Sources */,
FEFFD99126C1347D00F34231 /* ShareAppContentServiceRemote.swift in Sources */,
74585B8E1F0D51A100E7E667 /* DomainsServiceRemote.swift in Sources */,
FEAE3AC7298AC2A300E05A24 /* JetpackProxyServiceRemote.swift in Sources */,
4625B965253A343900C04AAD /* RemotePageLayouts.swift in Sources */,
FEF7419B2808591C002C4203 /* BloggingPromptsServiceRemote.swift in Sources */,
7430C9A41F1927180051B8E6 /* ReaderPostServiceRemote.m in Sources */,
Expand Down Expand Up @@ -3266,6 +3273,7 @@
FEE4EF5B27302317003CDA3C /* CommentServiceRemoteREST+APIv2Tests.swift in Sources */,
803DE81128FFA9C4007D4E9C /* RemoteConfigRemoteTests.swift in Sources */,
74B5F0DE1EF82A9600B411E7 /* BlogServiceRemoteRESTTests.m in Sources */,
FED77253298B819900C2346E /* JetpackProxyServiceRemoteTests.swift in Sources */,
ABD95B7F25DD6C4B00735BEE /* CommentServiceRemoteRESTLikesTests.swift in Sources */,
8B749E8225AF7DDA00023F03 /* JetpackCapabilitiesServiceRemoteTests.swift in Sources */,
74E2294B1F1E73340085F7F2 /* SharingServiceRemoteTests.m in Sources */,
Expand Down
58 changes: 58 additions & 0 deletions WordPressKit/JetpackProxyServiceRemote.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/// Encapsulates Jetpack Proxy requests.
public class JetpackProxyServiceRemote: ServiceRemoteWordPressComREST {

/// Represents the most common HTTP methods for the proxied request.
public enum DotComMethod: String {
case get
case post
case put
case delete
}

/// Sends a proxied request to a Jetpack-connected site through the Jetpack Proxy API.
/// The proxy API expects the client to be authenticated with a WordPress.com account.
///
/// - Parameters:
/// - siteID: The dotcom ID of the Jetpack-connected site.
/// - path: The request endpoint to be proxied.
/// - method: The HTTP method for the proxied request.
/// - parameters: The request parameter for the proxied request. Defaults to empty.
/// - locale: The user locale, if any. Defaults to nil.
/// - completion: Closure called after the request completes.
/// - Returns: A Progress object, which can be used to cancel the request if needed.
@discardableResult
public func proxyRequest(for siteID: Int,
path: String,
method: DotComMethod,
parameters: [String: AnyHashable] = [:],
locale: String? = nil,
completion: @escaping (Result<AnyObject, Error>) -> Void) -> Progress? {
let urlString = self.path(forEndpoint: "jetpack-blogs/\(siteID)/rest-api", withVersion: ._1_1)

// Construct the request parameters to be forwarded to the actual endpoint.
var requestParams: [String: AnyHashable] = [
"json": "true",
"path": "\(path)&_method=\(method.rawValue)"
]

// The parameters need to be encoded into a JSON string.
if !parameters.isEmpty,
let data = try? JSONSerialization.data(withJSONObject: parameters, options: []),
let jsonString = String(data: data, encoding: .utf8) {
// Use "query" for the body parameters if the method is GET. Otherwise, always use "body".
let bodyParameterKey = (method == .get ? "query" : "body")
requestParams[bodyParameterKey] = jsonString
}

if let locale,
!locale.isEmpty {
requestParams["locale"] = locale
}

return wordPressComRestApi.POST(urlString, parameters: requestParams as [String: AnyObject]) { response, _ in
completion(.success(response))
} failure: { error, _ in
completion(.failure(error))
}
}
}
122 changes: 122 additions & 0 deletions WordPressKitTests/JetpackProxyServiceRemoteTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import XCTest
@testable import WordPressKit

class JetpackProxyServiceRemoteTests: XCTestCase {
let timeout: TimeInterval = 1.0
let api = MockWordPressComRestApi()
let siteID = 1001

private var remote: JetpackProxyServiceRemote {
return .init(wordPressComRestApi: api)
}

// MARK: - Tests

func testProxyRequestEndpoint() {
// the mock rest API doesn't append the base URL, so we're just going to verify the path.
let urlString = "rest/v1.1/jetpack-blogs/\(siteID)/rest-api"

remote.proxyRequest(for: siteID, path: "path", method: .get) { _ in }

guard let passedURLString = api.URLStringPassedIn else {
return XCTFail()
}
XCTAssertTrue(passedURLString.hasSuffix(urlString))
}

func testJSONParameter() {
remote.proxyRequest(for: siteID, path: "path", method: .get) { _ in }

guard let passedParameter = api.parametersPassedIn as? [String: AnyObject] else {
return XCTFail()
}
XCTAssertEqual(passedParameter["json"] as? String, "true")
}

func testPathParameter() {
let path = "/wp/v2/posts"
let method = JetpackProxyServiceRemote.DotComMethod.get

remote.proxyRequest(for: siteID, path: path, method: method) { _ in }

guard let passedParameter = api.parametersPassedIn as? [String: AnyObject] else {
return XCTFail()
}
XCTAssertEqual(passedParameter["path"] as? String, "\(path)&_method=\(method.rawValue)")
}

func testBodyParameterKeyForGETMethod() {
let method = JetpackProxyServiceRemote.DotComMethod.get
let params = ["key": "value"]

remote.proxyRequest(for: siteID, path: "path", method: method, parameters: params) { _ in }

guard let passedParameter = api.parametersPassedIn as? [String: AnyObject] else {
return XCTFail()
}
XCTAssertNotNil(passedParameter["query"])
}

func testBodyParameterKeyForPOSTMethod() {
let method = JetpackProxyServiceRemote.DotComMethod.post
let params = ["key": "value"]

remote.proxyRequest(for: siteID, path: "path", method: method, parameters: params) { _ in }

guard let passedParameter = api.parametersPassedIn as? [String: AnyObject] else {
return XCTFail()
}
XCTAssertNotNil(passedParameter["body"])
}

func testBodyParameterEncoding() {
let method = JetpackProxyServiceRemote.DotComMethod.post
let params = [
"key1": "value1",
"key2": "value2"
]

remote.proxyRequest(for: siteID, path: "path", method: method, parameters: params) { _ in }

guard let passedParameter = api.parametersPassedIn as? [String: AnyObject],
let jsonString = passedParameter["body"] as? String,
let jsonData = jsonString.data(using: .utf8),
let jsonDictionary = try? JSONSerialization.jsonObject(with: jsonData, options: []) as? [String: String] else {
return XCTFail()
}
XCTAssertEqual(jsonDictionary, params)
}

func testBodyParameterShouldNotExistWhenEmpty() {
let params = [String: String]()

remote.proxyRequest(for: siteID, path: "path", method: .post, parameters: params) { _ in }

guard let passedParameter = api.parametersPassedIn as? [String: AnyObject] else {
return XCTFail()
}
XCTAssertNil(passedParameter["body"])
}

func testLocaleParameter() {
let locale = "en_US"

remote.proxyRequest(for: siteID, path: "path", method: .post, locale: locale) { _ in }

guard let passedParameter = api.parametersPassedIn as? [String: AnyObject] else {
return XCTFail()
}
XCTAssertEqual(passedParameter["locale"] as? String, locale)
}

func testLocaleParameterShouldNotExistWhenEmpty() {
let locale = String()

remote.proxyRequest(for: siteID, path: "path", method: .post, locale: locale) { _ in }

guard let passedParameter = api.parametersPassedIn as? [String: AnyObject] else {
return XCTFail()
}
XCTAssertNil(passedParameter["locale"])
}
}

0 comments on commit 2c2b4c3

Please sign in to comment.