From 96ae82f62e13909ff80ecdd05583f9177e39b4da Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Wed, 10 Apr 2024 08:04:54 +1000 Subject: [PATCH 01/18] Remove an `enum` builder in favor of default associated value --- Sources/WordPressKit/WordPressAPI/WordPressAPIError.swift | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Sources/WordPressKit/WordPressAPI/WordPressAPIError.swift b/Sources/WordPressKit/WordPressAPI/WordPressAPIError.swift index a4680b20..5a6c3d5f 100644 --- a/Sources/WordPressKit/WordPressAPI/WordPressAPIError.swift +++ b/Sources/WordPressKit/WordPressAPI/WordPressAPIError.swift @@ -18,13 +18,10 @@ public enum WordPressAPIError: Error where EndpointError: Localiz /// The API call returned an status code that's unacceptable to the endpoint. case unacceptableStatusCode(response: HTTPURLResponse, body: Data) /// The API call returned an HTTP response that WordPressKit can't parse. Receiving this error could be an indicator that there is an error response that's not handled properly by WordPressKit. - case unparsableResponse(response: HTTPURLResponse?, body: Data?, underlyingError: Error) + case unparsableResponse(response: HTTPURLResponse?, body: Data?, underlyingError: Error = URLError(.cannotParseResponse)) /// Other error occured. case unknown(underlyingError: Error) - static func unparsableResponse(response: HTTPURLResponse?, body: Data?) -> Self { - return WordPressAPIError.unparsableResponse(response: response, body: body, underlyingError: URLError(.cannotParseResponse)) - } var response: HTTPURLResponse? { switch self { From d17587a310bb41e15b5f0a666d7ae93b156f7242 Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Wed, 10 Apr 2024 07:46:23 +1000 Subject: [PATCH 02/18] Remove `PostServiceRemoteExtended` and implementations They will be moved into WordPress and Jetpack. The reason for this is that they are only used in WordPress and Jetpack and that they are Swift extensions of Objective-C types which we are trying to isolate. It's simpler to move these leaf types into the only consumer that uses them than trying to re-architect them. --- .../Services/PostServiceRemoteExtended.swift | 25 ------ .../PostServiceRemoteREST+Extended.swift | 67 ---------------- .../PostServiceRemoteXMLRPC+Extended.swift | 77 ------------------- WordPressKit.xcodeproj/project.pbxproj | 12 --- 4 files changed, 181 deletions(-) delete mode 100644 Sources/WordPressKit/Services/PostServiceRemoteExtended.swift delete mode 100644 Sources/WordPressKit/Services/PostServiceRemoteREST+Extended.swift delete mode 100644 Sources/WordPressKit/Services/PostServiceRemoteXMLRPC+Extended.swift diff --git a/Sources/WordPressKit/Services/PostServiceRemoteExtended.swift b/Sources/WordPressKit/Services/PostServiceRemoteExtended.swift deleted file mode 100644 index fb7ed17e..00000000 --- a/Sources/WordPressKit/Services/PostServiceRemoteExtended.swift +++ /dev/null @@ -1,25 +0,0 @@ -import Foundation - -public protocol PostServiceRemoteExtended: PostServiceRemote { - /// Creates a new post with the given parameters. - func createPost(with parameters: RemotePostCreateParameters) async throws -> RemotePost - - /// Performs a partial update to the existing post. - /// - /// - throws: ``PostServiceRemoteUpdatePostError`` or oher underlying errors - /// (see ``WordPressAPIError``) - func patchPost(withID postID: Int, parameters: RemotePostUpdateParameters) async throws -> RemotePost - - /// Permanently deletes a post with the given ID. - /// - /// - throws: ``PostServiceRemoteUpdatePostError`` or oher underlying errors - /// (see ``WordPressAPIError``) - func deletePost(withID postID: Int) async throws -} - -public enum PostServiceRemoteUpdatePostError: Error { - /// 409 (Conflict) - case conflict - /// 404 (Not Found) - case notFound -} diff --git a/Sources/WordPressKit/Services/PostServiceRemoteREST+Extended.swift b/Sources/WordPressKit/Services/PostServiceRemoteREST+Extended.swift deleted file mode 100644 index 6637a785..00000000 --- a/Sources/WordPressKit/Services/PostServiceRemoteREST+Extended.swift +++ /dev/null @@ -1,67 +0,0 @@ -import Foundation - -extension PostServiceRemoteREST: PostServiceRemoteExtended { - public func createPost(with parameters: RemotePostCreateParameters) async throws -> RemotePost { - let path = self.path(forEndpoint: "sites/\(siteID)/posts/new?context=edit", withVersion: ._1_2) - let parameters = try makeParameters(from: RemotePostCreateParametersWordPressComEncoder(parameters: parameters)) - - let response = try await wordPressComRestApi.perform(.post, URLString: path, parameters: parameters).get() - return try await decodePost(from: response.body) - } - - public func patchPost(withID postID: Int, parameters: RemotePostUpdateParameters) async throws -> RemotePost { - let path = self.path(forEndpoint: "sites/\(siteID)/posts/\(postID)?context=edit", withVersion: ._1_2) - let parameters = try makeParameters(from: RemotePostUpdateParametersWordPressComEncoder(parameters: parameters)) - - let result = await wordPressComRestApi.perform(.post, URLString: path, parameters: parameters) - switch result { - case .success(let response): - return try await decodePost(from: response.body) - case .failure(let error): - guard case .endpointError(let error) = error else { - throw error - } - switch error.apiErrorCode ?? "" { - case "unknown_post": throw PostServiceRemoteUpdatePostError.notFound - case "old-revision": throw PostServiceRemoteUpdatePostError.conflict - default: throw error - } - } - } - - public func deletePost(withID postID: Int) async throws { - let path = self.path(forEndpoint: "sites/\(siteID)/posts/\(postID)/delete", withVersion: ._1_1) - let result = await wordPressComRestApi.perform(.post, URLString: path) - switch result { - case .success: - return - case .failure(let error): - guard case .endpointError(let error) = error else { - throw error - } - switch error.apiErrorCode ?? "" { - case "unknown_post": throw PostServiceRemoteUpdatePostError.notFound - default: throw error - } - } - } -} - -// Decodes the post in the background. -private func decodePost(from object: AnyObject) async throws -> RemotePost { - guard let dictionary = object as? [AnyHashable: Any] else { - throw WordPressAPIError.unparsableResponse(response: nil, body: nil) - } - return PostServiceRemoteREST.remotePost(fromJSONDictionary: dictionary) -} - -private func makeParameters(from value: T) throws -> [String: AnyObject] { - let encoder = JSONEncoder() - encoder.dateEncodingStrategy = .formatted(.wordPressCom) - let data = try encoder.encode(value) - let object = try JSONSerialization.jsonObject(with: data) - guard let dictionary = object as? [String: AnyObject] else { - throw URLError(.unknown) // This should never happen - } - return dictionary -} diff --git a/Sources/WordPressKit/Services/PostServiceRemoteXMLRPC+Extended.swift b/Sources/WordPressKit/Services/PostServiceRemoteXMLRPC+Extended.swift deleted file mode 100644 index b1bccf1a..00000000 --- a/Sources/WordPressKit/Services/PostServiceRemoteXMLRPC+Extended.swift +++ /dev/null @@ -1,77 +0,0 @@ -import Foundation -import wpxmlrpc - -extension PostServiceRemoteXMLRPC: PostServiceRemoteExtended { - public func createPost(with parameters: RemotePostCreateParameters) async throws -> RemotePost { - let dictionary = try makeParameters(from: RemotePostCreateParametersXMLRPCEncoder(parameters: parameters)) - let parameters = xmlrpcArguments(withExtra: dictionary) as [AnyObject] - let response = try await api.call(method: "metaWeblog.newPost", parameters: parameters).get() - guard let postID = (response.body as? NSObject)?.numericValue() else { - throw URLError(.unknown) // Should never happen - } - return try await getPost(withID: postID) - } - - public func patchPost(withID postID: Int, parameters: RemotePostUpdateParameters) async throws -> RemotePost { - let dictionary = try makeParameters(from: RemotePostUpdateParametersXMLRPCEncoder(parameters: parameters)) - var parameters = xmlrpcArguments(withExtra: dictionary) as [AnyObject] - if parameters.count > 0 { - parameters[0] = postID as NSNumber - } - let result = await api.call(method: "metaWeblog.editPost", parameters: parameters) - switch result { - case .success: - return try await getPost(withID: postID as NSNumber) - case .failure(let error): - guard case .endpointError(let error) = error else { - throw error - } - switch error.code ?? 0 { - case 404: throw PostServiceRemoteUpdatePostError.notFound - case 409: throw PostServiceRemoteUpdatePostError.conflict - default: throw error - } - } - } - - public func deletePost(withID postID: Int) async throws { - let parameters = xmlrpcArguments(withExtra: postID) as [AnyObject] - let result = await api.call(method: "wp.deletePost", parameters: parameters) - switch result { - case .success: - return - case .failure(let error): - guard case .endpointError(let error) = error else { - throw error - } - switch error.code ?? 0 { - case 404: throw PostServiceRemoteUpdatePostError.notFound - default: throw error - } - } - } - - private func getPost(withID postID: NSNumber) async throws -> RemotePost { - try await withUnsafeThrowingContinuation { continuation in - getPostWithID(postID) { post in - guard let post else { - return continuation.resume(throwing: URLError(.unknown)) // Should never happen - } - continuation.resume(returning: post) - } failure: { error in - continuation.resume(throwing: error ?? URLError(.unknown)) - } - } - } -} - -private func makeParameters(from value: T) throws -> [String: AnyObject] { - let encoder = PropertyListEncoder() - encoder.outputFormat = .xml - let data = try encoder.encode(value) - let object = try PropertyListSerialization.propertyList(from: data, format: nil) - guard let dictionary = object as? [String: AnyObject] else { - throw URLError(.unknown) // This should never happen - } - return dictionary -} diff --git a/WordPressKit.xcodeproj/project.pbxproj b/WordPressKit.xcodeproj/project.pbxproj index 393460ce..7a663384 100644 --- a/WordPressKit.xcodeproj/project.pbxproj +++ b/WordPressKit.xcodeproj/project.pbxproj @@ -13,9 +13,6 @@ 0152100C28EDA9E400DD6783 /* StatsAnnualAndMostPopularTimeInsightDecodingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0152100B28EDA9E400DD6783 /* StatsAnnualAndMostPopularTimeInsightDecodingTests.swift */; }; 0847B92C2A4442730044D32F /* IPLocationRemote.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0847B92B2A4442730044D32F /* IPLocationRemote.swift */; }; 08C7493E2A45EA11000DA0E2 /* IPLocationRemoteTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 08C7493D2A45EA11000DA0E2 /* IPLocationRemoteTests.swift */; }; - 0C1C08412B9CD79900E52F8C /* PostServiceRemoteExtended.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C1C08402B9CD79900E52F8C /* PostServiceRemoteExtended.swift */; }; - 0C1C08432B9CD8D200E52F8C /* PostServiceRemoteREST+Extended.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C1C08422B9CD8D200E52F8C /* PostServiceRemoteREST+Extended.swift */; }; - 0C1C08452B9CDB0B00E52F8C /* PostServiceRemoteXMLRPC+Extended.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C1C08442B9CDB0B00E52F8C /* PostServiceRemoteXMLRPC+Extended.swift */; }; 0C9CD7992B9A107E0045BE03 /* RemotePostParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C9CD7982B9A107E0045BE03 /* RemotePostParameters.swift */; }; 0CB1905E2A2A5E83004D3E80 /* BlazeCampaign.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CB1905D2A2A5E83004D3E80 /* BlazeCampaign.swift */; }; 0CB190612A2A6A13004D3E80 /* blaze-campaigns-search.json in Resources */ = {isa = PBXBuildFile; fileRef = 0CB1905F2A2A6943004D3E80 /* blaze-campaigns-search.json */; }; @@ -757,9 +754,6 @@ 0152100B28EDA9E400DD6783 /* StatsAnnualAndMostPopularTimeInsightDecodingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatsAnnualAndMostPopularTimeInsightDecodingTests.swift; sourceTree = ""; }; 0847B92B2A4442730044D32F /* IPLocationRemote.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IPLocationRemote.swift; sourceTree = ""; }; 08C7493D2A45EA11000DA0E2 /* IPLocationRemoteTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IPLocationRemoteTests.swift; sourceTree = ""; }; - 0C1C08402B9CD79900E52F8C /* PostServiceRemoteExtended.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostServiceRemoteExtended.swift; sourceTree = ""; }; - 0C1C08422B9CD8D200E52F8C /* PostServiceRemoteREST+Extended.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PostServiceRemoteREST+Extended.swift"; sourceTree = ""; }; - 0C1C08442B9CDB0B00E52F8C /* PostServiceRemoteXMLRPC+Extended.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PostServiceRemoteXMLRPC+Extended.swift"; sourceTree = ""; }; 0C3A2A412A2E7BA500FD91D6 /* CHANGELOG.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = CHANGELOG.md; sourceTree = ""; }; 0C9CD7982B9A107E0045BE03 /* RemotePostParameters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemotePostParameters.swift; sourceTree = ""; }; 0CB1905D2A2A5E83004D3E80 /* BlazeCampaign.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlazeCampaign.swift; sourceTree = ""; }; @@ -1779,15 +1773,12 @@ E1BD95141FD5A2B800CD5CE3 /* PluginDirectoryServiceRemote.swift */, E13EE1461F33258E00C15787 /* PluginServiceRemote.swift */, 740B23B21F17EC7300067A2A /* PostServiceRemote.h */, - 0C1C08402B9CD79900E52F8C /* PostServiceRemoteExtended.swift */, 740B23BC1F17ECB500067A2A /* PostServiceRemoteOptions.h */, 740B23B31F17EC7300067A2A /* PostServiceRemoteREST.h */, 740B23B41F17EC7300067A2A /* PostServiceRemoteREST.m */, - 0C1C08422B9CD8D200E52F8C /* PostServiceRemoteREST+Extended.swift */, 9AF4F2FB218331DC00570E4B /* PostServiceRemoteREST+Revisions.swift */, 740B23B51F17EC7300067A2A /* PostServiceRemoteXMLRPC.h */, 740B23B61F17EC7300067A2A /* PostServiceRemoteXMLRPC.m */, - 0C1C08442B9CDB0B00E52F8C /* PostServiceRemoteXMLRPC+Extended.swift */, F181EA0127184D3C00F26141 /* ProductServiceRemote.swift */, 74A44DCA1F13C533006CD8F4 /* PushAuthenticationServiceRemote.swift */, C7A09A4F284104DB003096ED /* QR Login */, @@ -3342,18 +3333,15 @@ 436D56352118D85800CEAA33 /* WPCountry.swift in Sources */, 74A44DCB1F13C533006CD8F4 /* NotificationSettingsServiceRemote.swift in Sources */, FAD1344525908F5F00A8FEB1 /* JetpackBackupServiceRemote.swift in Sources */, - 0C1C08452B9CDB0B00E52F8C /* PostServiceRemoteXMLRPC+Extended.swift in Sources */, F1BB7806240FB90B0030ADDC /* AtomicAuthenticationServiceRemote.swift in Sources */, 404057CE221C38130060250C /* StatsTopVideosTimeIntervalData.swift in Sources */, 7E0D64FF22D855700092AD10 /* EditorServiceRemote.swift in Sources */, - 0C1C08412B9CD79900E52F8C /* PostServiceRemoteExtended.swift in Sources */, 9AF4F2FF2183346B00570E4B /* RemoteRevision.swift in Sources */, FE6C673A2BB739950083ECAB /* Decodable+Dictionary.swift in Sources */, 17D936252475D8AB008B2205 /* RemoteHomepageType.swift in Sources */, 74BA04F41F06DC0A00ED5CD8 /* CommentServiceRemoteREST.m in Sources */, 74C473AC1EF2F75E009918F2 /* SiteManagementServiceRemote.swift in Sources */, 74585B971F0D54B400E7E667 /* RemoteDomain.swift in Sources */, - 0C1C08432B9CD8D200E52F8C /* PostServiceRemoteREST+Extended.swift in Sources */, 3FFCC0492BAB98130051D229 /* DateFormatter+WordPressCom.swift in Sources */, 74A44DD01F13C64B006CD8F4 /* RemoteNotification.swift in Sources */, E1D6B558200E473A00325669 /* TimeZoneServiceRemote.swift in Sources */, From 58a63866fd064c2760cc4649880a0a3aed190c17 Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Wed, 10 Apr 2024 08:03:53 +1000 Subject: [PATCH 03/18] Update access control to components called by removed types --- .../Models/RemotePostParameters.swift | 32 ++++++++++++++----- .../DateFormatter+WordPressCom.swift | 2 +- .../WordPressAPI/HTTPRequestBuilder.swift | 4 +-- .../WordPressAPI/WordPressComRestApi.swift | 2 +- .../WordPressAPI/WordPressOrgXMLRPCApi.swift | 2 +- 5 files changed, 29 insertions(+), 13 deletions(-) diff --git a/Sources/WordPressKit/Models/RemotePostParameters.swift b/Sources/WordPressKit/Models/RemotePostParameters.swift index 81849b09..f1abb0bb 100644 --- a/Sources/WordPressKit/Models/RemotePostParameters.swift +++ b/Sources/WordPressKit/Models/RemotePostParameters.swift @@ -177,10 +177,14 @@ private enum RemotePostWordPressComCodingKeys: String, CodingKey { static let postTags = "post_tag" } -struct RemotePostCreateParametersWordPressComEncoder: Encodable { +public struct RemotePostCreateParametersWordPressComEncoder: Encodable { let parameters: RemotePostCreateParameters - func encode(to encoder: Encoder) throws { + public init(parameters: RemotePostCreateParameters) { + self.parameters = parameters + } + + public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: RemotePostWordPressComCodingKeys.self) try container.encodeIfPresent(parameters.type, forKey: .type) try container.encodeIfPresent(parameters.status, forKey: .status) @@ -212,10 +216,14 @@ struct RemotePostCreateParametersWordPressComEncoder: Encodable { } } -struct RemotePostUpdateParametersWordPressComEncoder: Encodable { +public struct RemotePostUpdateParametersWordPressComEncoder: Encodable { let parameters: RemotePostUpdateParameters - func encode(to encoder: Encoder) throws { + public init(parameters: RemotePostUpdateParameters) { + self.parameters = parameters + } + + public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: RemotePostWordPressComCodingKeys.self) try container.encodeIfPresent(parameters.ifNotModifiedSince, forKey: .ifNotModifiedSince) @@ -274,10 +282,14 @@ private enum RemotePostXMLRPCCodingKeys: String, CodingKey { static let postTags = "post_tag" } -struct RemotePostCreateParametersXMLRPCEncoder: Encodable { +public struct RemotePostCreateParametersXMLRPCEncoder: Encodable { let parameters: RemotePostCreateParameters - func encode(to encoder: Encoder) throws { + public init(parameters: RemotePostCreateParameters) { + self.parameters = parameters + } + + public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: RemotePostXMLRPCCodingKeys.self) try container.encode(parameters.type, forKey: .type) try container.encodeIfPresent(parameters.status, forKey: .postStatus) @@ -309,10 +321,14 @@ struct RemotePostCreateParametersXMLRPCEncoder: Encodable { } } -struct RemotePostUpdateParametersXMLRPCEncoder: Encodable { +public struct RemotePostUpdateParametersXMLRPCEncoder: Encodable { let parameters: RemotePostUpdateParameters - func encode(to encoder: Encoder) throws { + public init(parameters: RemotePostUpdateParameters) { + self.parameters = parameters + } + + public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: RemotePostXMLRPCCodingKeys.self) try container.encodeIfPresent(parameters.ifNotModifiedSince, forKey: .ifNotModifiedSince) try container.encodeIfPresent(parameters.status, forKey: .postStatus) diff --git a/Sources/WordPressKit/WordPressAPI/DateFormatter+WordPressCom.swift b/Sources/WordPressKit/WordPressAPI/DateFormatter+WordPressCom.swift index 1bb03baf..a20a1775 100644 --- a/Sources/WordPressKit/WordPressAPI/DateFormatter+WordPressCom.swift +++ b/Sources/WordPressKit/WordPressAPI/DateFormatter+WordPressCom.swift @@ -3,7 +3,7 @@ extension DateFormatter { /// A `DateFormatter` configured to manage dates compatible with the WordPress.com API. /// /// - SeeAlso: [https://developer.wordpress.com/docs/api/](https://developer.wordpress.com/docs/api/) - static let wordPressCom: DateFormatter = { + public static let wordPressCom: DateFormatter = { let formatter = DateFormatter() formatter.dateFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ssZ" formatter.timeZone = NSTimeZone(forSecondsFromGMT: 0) as TimeZone diff --git a/Sources/WordPressKit/WordPressAPI/HTTPRequestBuilder.swift b/Sources/WordPressKit/WordPressAPI/HTTPRequestBuilder.swift index c53cf9ca..bb26a907 100644 --- a/Sources/WordPressKit/WordPressAPI/HTTPRequestBuilder.swift +++ b/Sources/WordPressKit/WordPressAPI/HTTPRequestBuilder.swift @@ -5,8 +5,8 @@ import wpxmlrpc /// /// Calling this class's url related functions (the ones that changes path, query, etc) does not modify the /// original URL string. The URL will be perserved in the final result that's returned by the `build` function. -final class HTTPRequestBuilder { - enum Method: String, CaseIterable { +public final class HTTPRequestBuilder { + public enum Method: String, CaseIterable { case get = "GET" case post = "POST" case put = "PUT" diff --git a/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift b/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift index a0b9d605..64e875ad 100644 --- a/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift +++ b/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift @@ -360,7 +360,7 @@ open class WordPressComRestApi: NSObject { return configuration } - func perform( + public func perform( _ method: HTTPRequestBuilder.Method, URLString: String, parameters: [String: AnyObject]? = nil, diff --git a/Sources/WordPressKit/WordPressAPI/WordPressOrgXMLRPCApi.swift b/Sources/WordPressKit/WordPressAPI/WordPressOrgXMLRPCApi.swift index 2698c89f..4bb825eb 100644 --- a/Sources/WordPressKit/WordPressAPI/WordPressOrgXMLRPCApi.swift +++ b/Sources/WordPressKit/WordPressAPI/WordPressOrgXMLRPCApi.swift @@ -180,7 +180,7 @@ open class WordPressOrgXMLRPCApi: NSObject { /// - Parameters: /// - streaming: set to `true` if there are large data (i.e. uploading files) in given `parameters`. `false` by default. /// - Returns: A `Result` type that contains the XMLRPC success or failure result. - func call(method: String, parameters: [AnyObject]?, fulfilling progress: Progress? = nil, streaming: Bool = false) async -> WordPressAPIResult, WordPressOrgXMLRPCApiFault> { + public func call(method: String, parameters: [AnyObject]?, fulfilling progress: Progress? = nil, streaming: Bool = false) async -> WordPressAPIResult, WordPressOrgXMLRPCApiFault> { let session = streaming ? uploadURLSession : urlSession let builder = HTTPRequestBuilder(url: endpoint) .method(.post) From 19bbd29b298c50df88923849c2a2e531b8c68a6e Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Wed, 10 Apr 2024 08:30:22 +1000 Subject: [PATCH 04/18] Move `upload(...` definition before `perform(...` This is just a convenience refactor to make future diff clearer --- .../WordPressAPI/WordPressComRestApi.swift | 65 +++++++++---------- 1 file changed, 32 insertions(+), 33 deletions(-) diff --git a/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift b/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift index 64e875ad..5fe6d288 100644 --- a/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift +++ b/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift @@ -360,6 +360,38 @@ open class WordPressComRestApi: NSObject { return configuration } + public func upload( + URLString: String, + parameters: [String: AnyObject]?, + fileParts: [FilePart], + requestEnqueued: RequestEnqueuedBlock? = nil, + fulfilling progress: Progress? = nil + ) async -> APIResult { + let builder: HTTPRequestBuilder + do { + let form = try fileParts.map { + try MultipartFormField(fileAtPath: $0.url.path, name: $0.parameterName, filename: $0.fileName, mimeType: $0.mimeType) + } + builder = try requestBuilder(URLString: URLString) + .method(.post) + .body(form: form) + } catch { + return .failure(.requestEncodingFailure(underlyingError: error)) + } + + return await perform( + request: builder.query(parameters ?? [:]), + fulfilling: progress, + decoder: { try JSONSerialization.jsonObject(with: $0) as AnyObject }, + taskCreated: { taskID in + DispatchQueue.main.async { + requestEnqueued?(NSNumber(value: taskID)) + } + }, + session: uploadURLSession + ) + } + public func perform( _ method: HTTPRequestBuilder.Method, URLString: String, @@ -443,39 +475,6 @@ open class WordPressComRestApi: NSObject { } } } - - public func upload( - URLString: String, - parameters: [String: AnyObject]?, - fileParts: [FilePart], - requestEnqueued: RequestEnqueuedBlock? = nil, - fulfilling progress: Progress? = nil - ) async -> APIResult { - let builder: HTTPRequestBuilder - do { - let form = try fileParts.map { - try MultipartFormField(fileAtPath: $0.url.path, name: $0.parameterName, filename: $0.fileName, mimeType: $0.mimeType) - } - builder = try requestBuilder(URLString: URLString) - .method(.post) - .body(form: form) - } catch { - return .failure(.requestEncodingFailure(underlyingError: error)) - } - - return await perform( - request: builder.query(parameters ?? [:]), - fulfilling: progress, - decoder: { try JSONSerialization.jsonObject(with: $0) as AnyObject }, - taskCreated: { taskID in - DispatchQueue.main.async { - requestEnqueued?(NSNumber(value: taskID)) - } - }, - session: uploadURLSession - ) - } - } // MARK: - Error processing From 61dbb4e64e8d6199f5cd449b9ea5b845aa31dc4b Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Wed, 10 Apr 2024 08:31:38 +1000 Subject: [PATCH 05/18] Make a couple of properties used in `async` API `public` --- .../APIInterface/include/WordPressComRESTAPIInterfacing.h | 6 ++++++ Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Sources/APIInterface/include/WordPressComRESTAPIInterfacing.h b/Sources/APIInterface/include/WordPressComRESTAPIInterfacing.h index 1f652fd6..7901238d 100644 --- a/Sources/APIInterface/include/WordPressComRESTAPIInterfacing.h +++ b/Sources/APIInterface/include/WordPressComRESTAPIInterfacing.h @@ -6,6 +6,12 @@ @property (strong, nonatomic, readonly) NSURL * _Nonnull baseURL; +/// The key with which to specify locale in the parameters of a request. +@property (strong, nonatomic, readonly) NSString * _Nonnull localeKey; + +/// Whether the user's preferred language locale should be appended. +@property (nonatomic, readonly) BOOL appendsPreferredLanguageLocale; + /// - Note: `parameters` has `id` instead of the more common `NSObject *` as its value type so it will convert to `AnyObject` in Swift. /// In Swift, it's simpler to work with `AnyObject` than with `NSObject`. For example `"abc" as AnyObject` over `"abc" as NSObject`. - (NSProgress * _Nullable)get:(NSString * _Nonnull)URLString diff --git a/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift b/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift index 5fe6d288..7b81070a 100644 --- a/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift +++ b/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift @@ -95,7 +95,7 @@ open class WordPressComRestApi: NSObject { private let backgroundUploads: Bool - private let localeKey: String + public let localeKey: String @objc public let baseURL: URL From 5571b0381992bcda0084c33d743a49f43c24fd07 Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Wed, 10 Apr 2024 08:41:22 +1000 Subject: [PATCH 06/18] Remove a stray double new line --- Sources/WordPressKit/WordPressAPI/WordPressAPIError.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/Sources/WordPressKit/WordPressAPI/WordPressAPIError.swift b/Sources/WordPressKit/WordPressAPI/WordPressAPIError.swift index 5a6c3d5f..508710f1 100644 --- a/Sources/WordPressKit/WordPressAPI/WordPressAPIError.swift +++ b/Sources/WordPressKit/WordPressAPI/WordPressAPIError.swift @@ -22,7 +22,6 @@ public enum WordPressAPIError: Error where EndpointError: Localiz /// Other error occured. case unknown(underlyingError: Error) - var response: HTTPURLResponse? { switch self { case .requestEncodingFailure, .connection, .unknown: From be9635feb6a3f82db6780280018a2f9a0ff00159 Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Wed, 10 Apr 2024 08:41:38 +1000 Subject: [PATCH 07/18] Move `processError` to an extension on `WordPressComRESTAPIInterfacing` --- .../WordPressAPI/WordPressComRestApi.swift | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift b/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift index 7b81070a..3fb955ef 100644 --- a/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift +++ b/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift @@ -458,7 +458,7 @@ open class WordPressComRestApi: NSObject { return HTTPAPIResponse(response: response.response, body: object) } .mapUnacceptableStatusCodeError { response, body in - if let error = self.processError(response: response, body: body, additionalUserInfo: nil) { + if let error = self.processError(response: response, body: body, additionalUserInfo: nil, invalidTokenHandler: invalidTokenHandler) { return error } @@ -479,9 +479,14 @@ open class WordPressComRestApi: NSObject { // MARK: - Error processing -extension WordPressComRestApi { +extension WordPressComRESTAPIInterfacing { - func processError(response httpResponse: HTTPURLResponse, body data: Data, additionalUserInfo: [String: Any]?) -> WordPressComRestApiEndpointError? { + func processError( + response httpResponse: HTTPURLResponse, + body data: Data, + additionalUserInfo: [String: Any]?, + invalidTokenHandler: (() -> Void)? + ) -> WordPressComRestApiEndpointError? { // Not sure if it's intentional to include 500 status code, but the code seems to be there from the very beginning. // https://github.com/wordpress-mobile/WordPressKit-iOS/blob/1.0.1/WordPressKit/WordPressComRestApi.swift#L374 guard (400...500).contains(httpResponse.statusCode) else { @@ -527,7 +532,7 @@ extension WordPressComRestApi { if mappedError == .invalidToken { // Call `invalidTokenHandler in the main thread since it's typically used by the apps to present an authentication UI. DispatchQueue.main.async { - self.invalidTokenHandler?() + invalidTokenHandler?() } } From 61f6a44a508ead4f1c3ad40410e2968d734f752a Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Wed, 10 Apr 2024 08:42:53 +1000 Subject: [PATCH 08/18] Require `URLSession` in root `async` `perform` method --- Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift b/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift index 3fb955ef..7713d355 100644 --- a/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift +++ b/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift @@ -440,7 +440,7 @@ open class WordPressComRestApi: NSObject { } } - return await perform(request: builder, fulfilling: progress, decoder: decoder) + return await perform(request: builder, fulfilling: progress, decoder: decoder, session: urlSession) } private func perform( @@ -448,9 +448,9 @@ open class WordPressComRestApi: NSObject { fulfilling progress: Progress?, decoder: @escaping (Data) throws -> T, taskCreated: ((Int) -> Void)? = nil, - session: URLSession? = nil + session: URLSession ) async -> APIResult { - await (session ?? self.urlSession) + await session .perform(request: request, taskCreated: taskCreated, fulfilling: progress, errorType: WordPressComRestApiEndpointError.self) .mapSuccess { response -> HTTPAPIResponse in let object = try decoder(response.body) From b03cc2d4cddcba4de96f46a26a06a4584cb420e8 Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Wed, 10 Apr 2024 08:43:46 +1000 Subject: [PATCH 09/18] Move `session` argument before `taskCreated` As per Swift API naming guidelines on arguments with default values --- .../WordPressKit/WordPressAPI/WordPressComRestApi.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift b/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift index 7713d355..7b00a908 100644 --- a/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift +++ b/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift @@ -383,12 +383,12 @@ open class WordPressComRestApi: NSObject { request: builder.query(parameters ?? [:]), fulfilling: progress, decoder: { try JSONSerialization.jsonObject(with: $0) as AnyObject }, + session: uploadURLSession, taskCreated: { taskID in DispatchQueue.main.async { requestEnqueued?(NSNumber(value: taskID)) } - }, - session: uploadURLSession + } ) } @@ -447,8 +447,8 @@ open class WordPressComRestApi: NSObject { request: HTTPRequestBuilder, fulfilling progress: Progress?, decoder: @escaping (Data) throws -> T, - taskCreated: ((Int) -> Void)? = nil, - session: URLSession + session: URLSession, + taskCreated: ((Int) -> Void)? = nil ) async -> APIResult { await session .perform(request: request, taskCreated: taskCreated, fulfilling: progress, errorType: WordPressComRestApiEndpointError.self) From a5edf0deb3a0935aacca3024623ff587fde4bf81 Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Wed, 10 Apr 2024 08:47:25 +1000 Subject: [PATCH 10/18] Require `invalidTokenHandler` in `perform` --- .../WordPressAPI/WordPressComRestApi.swift | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift b/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift index 7b00a908..0157e6d6 100644 --- a/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift +++ b/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift @@ -384,6 +384,7 @@ open class WordPressComRestApi: NSObject { fulfilling: progress, decoder: { try JSONSerialization.jsonObject(with: $0) as AnyObject }, session: uploadURLSession, + invalidTokenHandler: invalidTokenHandler, taskCreated: { taskID in DispatchQueue.main.async { requestEnqueued?(NSNumber(value: taskID)) @@ -440,7 +441,13 @@ open class WordPressComRestApi: NSObject { } } - return await perform(request: builder, fulfilling: progress, decoder: decoder, session: urlSession) + return await perform( + request: builder, + fulfilling: progress, + decoder: decoder, + session: urlSession, + invalidTokenHandler: invalidTokenHandler + ) } private func perform( @@ -448,6 +455,7 @@ open class WordPressComRestApi: NSObject { fulfilling progress: Progress?, decoder: @escaping (Data) throws -> T, session: URLSession, + invalidTokenHandler: (() -> Void)?, taskCreated: ((Int) -> Void)? = nil ) async -> APIResult { await session From 68e32b870c8270caa1175a861a6c07fde8165f88 Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Wed, 10 Apr 2024 08:50:27 +1000 Subject: [PATCH 11/18] Move root `perform` definition to `WordPressComRESTAPIInterfacing` --- .../WordPressKit/WordPressAPI/WordPressComRestApi.swift | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift b/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift index 0157e6d6..d4172bf9 100644 --- a/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift +++ b/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift @@ -449,15 +449,18 @@ open class WordPressComRestApi: NSObject { invalidTokenHandler: invalidTokenHandler ) } +} - private func perform( +extension WordPressComRESTAPIInterfacing { + + func perform( request: HTTPRequestBuilder, fulfilling progress: Progress?, decoder: @escaping (Data) throws -> T, session: URLSession, invalidTokenHandler: (() -> Void)?, taskCreated: ((Int) -> Void)? = nil - ) async -> APIResult { + ) async -> WordPressAPIResult, WordPressComRestApiEndpointError> { await session .perform(request: request, taskCreated: taskCreated, fulfilling: progress, errorType: WordPressComRestApiEndpointError.self) .mapSuccess { response -> HTTPAPIResponse in From 16f2af7629478920639ef339fde997221dd84e22 Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Wed, 10 Apr 2024 09:05:12 +1000 Subject: [PATCH 12/18] Extract logic to create builder with locale to extension --- .../WordPressAPI/WordPressComRestApi.swift | 36 ++++++++++++++----- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift b/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift index d4172bf9..d3a165cf 100644 --- a/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift +++ b/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift @@ -307,18 +307,14 @@ open class WordPressComRestApi: NSObject { } private func requestBuilder(URLString: String) throws -> HTTPRequestBuilder { - guard let url = URL(string: URLString, relativeTo: baseURL) else { - throw URLError(.badURL) - } - - var builder = HTTPRequestBuilder(url: url) - + let locale: (String, String)? if appendsPreferredLanguageLocale { - let preferredLanguageIdentifier = WordPressComLanguageDatabase().deviceLanguage.slug - builder = builder.query(defaults: [URLQueryItem(name: localeKey, value: preferredLanguageIdentifier)]) + locale = (localeKey, WordPressComLanguageDatabase().deviceLanguage.slug) + } else { + locale = nil } - return builder + return try HTTPRequestBuilder.with(URLString: URLString, relativeTo: baseURL, appendingLocale: locale) } @objc public func temporaryFileURL(withExtension fileExtension: String) -> URL { @@ -579,6 +575,28 @@ extension WordPressComRESTAPIInterfacing { ) } } + +extension HTTPRequestBuilder { + + static func with( + URLString: String, + relativeTo baseURL: URL, + appendingLocale locale: (key: String, value: String)? + ) throws -> HTTPRequestBuilder { + guard let url = URL(string: URLString, relativeTo: baseURL) else { + throw URLError(.badURL) + } + + let builder = Self.init(url: url) + + guard let locale else { + return builder + } + + return builder.query(defaults: [URLQueryItem(name: locale.key, value: locale.value)]) + } + +} // MARK: - Anonymous API support extension WordPressComRestApi { From 63ac625b7a5e91d5aa176118e1d9e8ee991e4163 Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Wed, 10 Apr 2024 09:16:16 +1000 Subject: [PATCH 13/18] Add new `localeValue` property to `WordPressComRESTAPIInterfacing` --- .../include/WordPressComRESTAPIInterfacing.h | 10 ++++++++-- .../WordPressAPI/WordPressComRestApi.swift | 4 ++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/Sources/APIInterface/include/WordPressComRESTAPIInterfacing.h b/Sources/APIInterface/include/WordPressComRESTAPIInterfacing.h index 7901238d..35abe211 100644 --- a/Sources/APIInterface/include/WordPressComRESTAPIInterfacing.h +++ b/Sources/APIInterface/include/WordPressComRESTAPIInterfacing.h @@ -6,11 +6,17 @@ @property (strong, nonatomic, readonly) NSURL * _Nonnull baseURL; +/// Whether the user's preferred language locale should be appended to the request. +/// Should default to `true`. +/// +/// - SeeAlso: `localeKey` and `localeValue` to configure the locale appendend to the request. +@property (nonatomic, readonly) BOOL appendsPreferredLanguageLocale; + /// The key with which to specify locale in the parameters of a request. @property (strong, nonatomic, readonly) NSString * _Nonnull localeKey; -/// Whether the user's preferred language locale should be appended. -@property (nonatomic, readonly) BOOL appendsPreferredLanguageLocale; +/// The value with which to specify locale in the parameters of a request. +@property (strong, nonatomic, readonly) NSString * _Nonnull localeValue; /// - Note: `parameters` has `id` instead of the more common `NSObject *` as its value type so it will convert to `AnyObject` in Swift. /// In Swift, it's simpler to work with `AnyObject` than with `NSObject`. For example `"abc" as AnyObject` over `"abc" as NSObject`. diff --git a/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift b/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift index d3a165cf..1bb2976f 100644 --- a/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift +++ b/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift @@ -97,6 +97,10 @@ open class WordPressComRestApi: NSObject { public let localeKey: String + public var localeValue: String { + WordPressComLanguageDatabase().deviceLanguage.slug + } + @objc public let baseURL: URL private var invalidTokenHandler: (() -> Void)? From b09ee316f6d049dd92c678c4c837ec812c851b30 Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Wed, 10 Apr 2024 09:16:43 +1000 Subject: [PATCH 14/18] Move request builder to `WordPressComRESTAPIInterfacing` extension --- .../WordPressAPI/WordPressComRestApi.swift | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift b/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift index 1bb2976f..579b632b 100644 --- a/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift +++ b/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift @@ -310,17 +310,6 @@ open class WordPressComRestApi: NSObject { return "\(String(describing: oAuthToken)),\(String(describing: userAgent))".hashValue } - private func requestBuilder(URLString: String) throws -> HTTPRequestBuilder { - let locale: (String, String)? - if appendsPreferredLanguageLocale { - locale = (localeKey, WordPressComLanguageDatabase().deviceLanguage.slug) - } else { - locale = nil - } - - return try HTTPRequestBuilder.with(URLString: URLString, relativeTo: baseURL, appendingLocale: locale) - } - @objc public func temporaryFileURL(withExtension fileExtension: String) -> URL { assert(!fileExtension.isEmpty, "file Extension cannot be empty") let fileName = "\(ProcessInfo.processInfo.globallyUniqueString)_file.\(fileExtension)" @@ -427,8 +416,7 @@ open class WordPressComRestApi: NSObject { ) async -> APIResult { var builder: HTTPRequestBuilder do { - builder = try requestBuilder(URLString: URLString) - .method(method) + builder = try requestBuilder(URLString: URLString).method(method) } catch { return .failure(.requestEncodingFailure(underlyingError: error)) } @@ -486,6 +474,17 @@ extension WordPressComRESTAPIInterfacing { } } } + + func requestBuilder(URLString: String) throws -> HTTPRequestBuilder { + let locale: (String, String)? + if appendsPreferredLanguageLocale { + locale = (localeKey, localeValue) + } else { + locale = nil + } + + return try HTTPRequestBuilder.with(URLString: URLString, relativeTo: baseURL, appendingLocale: locale) + } } // MARK: - Error processing From 72c8f7bd0792d1c6bb53f421d9cbca31843e760d Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Wed, 10 Apr 2024 09:20:35 +1000 Subject: [PATCH 15/18] Redefine `APIResult` typealias in the context of `WPComRESTAPIInterfacing` --- Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift b/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift index 579b632b..3287a956 100644 --- a/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift +++ b/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift @@ -441,6 +441,8 @@ open class WordPressComRestApi: NSObject { extension WordPressComRESTAPIInterfacing { + public typealias APIResult = WordPressAPIResult, WordPressComRestApiEndpointError> + func perform( request: HTTPRequestBuilder, fulfilling progress: Progress?, @@ -448,7 +450,7 @@ extension WordPressComRESTAPIInterfacing { session: URLSession, invalidTokenHandler: (() -> Void)?, taskCreated: ((Int) -> Void)? = nil - ) async -> WordPressAPIResult, WordPressComRestApiEndpointError> { + ) async -> APIResult { await session .perform(request: request, taskCreated: taskCreated, fulfilling: progress, errorType: WordPressComRestApiEndpointError.self) .mapSuccess { response -> HTTPAPIResponse in From ed6a6349a5ba6803b2f3235747d710a4031c4677 Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Wed, 10 Apr 2024 09:39:38 +1000 Subject: [PATCH 16/18] Move `urlSession` and `invalidTokenHandler` to API interface protocol --- .../APIInterface/include/WordPressComRESTAPIInterfacing.h | 4 ++++ .../WordPressKit/WordPressAPI/WordPressComRestApi.swift | 7 ++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Sources/APIInterface/include/WordPressComRESTAPIInterfacing.h b/Sources/APIInterface/include/WordPressComRESTAPIInterfacing.h index 35abe211..5590ba14 100644 --- a/Sources/APIInterface/include/WordPressComRESTAPIInterfacing.h +++ b/Sources/APIInterface/include/WordPressComRESTAPIInterfacing.h @@ -18,6 +18,10 @@ /// The value with which to specify locale in the parameters of a request. @property (strong, nonatomic, readonly) NSString * _Nonnull localeValue; +@property (strong, nonatomic, readonly) NSURLSession * _Nonnull urlSession; + +@property (strong, nonatomic, readonly) void (^ _Nullable invalidTokenHandler)(void); + /// - Note: `parameters` has `id` instead of the more common `NSObject *` as its value type so it will convert to `AnyObject` in Swift. /// In Swift, it's simpler to work with `AnyObject` than with `NSObject`. For example `"abc" as AnyObject` over `"abc" as NSObject`. - (NSProgress * _Nullable)get:(NSString * _Nonnull)URLString diff --git a/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift b/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift index 3287a956..d5ae17b4 100644 --- a/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift +++ b/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift @@ -103,7 +103,7 @@ open class WordPressComRestApi: NSObject { @objc public let baseURL: URL - private var invalidTokenHandler: (() -> Void)? + public var invalidTokenHandler: (() -> Void)? /** Configure whether or not the user's preferred language locale should be appended. Defaults to true. @@ -177,9 +177,6 @@ open class WordPressComRestApi: NSObject { } } - @objc func setInvalidTokenHandler(_ handler: @escaping () -> Void) { - invalidTokenHandler = handler - } // MARK: Network requests @@ -319,7 +316,7 @@ open class WordPressComRestApi: NSObject { // MARK: - Async - private lazy var urlSession: URLSession = { + public lazy var urlSession: URLSession = { URLSession(configuration: sessionConfiguration(background: false)) }() From 55d8e8fa55153c22475d6b5befb321d14b1f3b6d Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Wed, 10 Apr 2024 09:41:01 +1000 Subject: [PATCH 17/18] Move a couple more `perform` types to API protocol --- .../WordPressAPI/WordPressComRestApi.swift | 38 ++++++++++--------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift b/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift index d5ae17b4..c75407ef 100644 --- a/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift +++ b/Sources/WordPressKit/WordPressAPI/WordPressComRestApi.swift @@ -379,17 +379,6 @@ open class WordPressComRestApi: NSObject { ) } - public func perform( - _ method: HTTPRequestBuilder.Method, - URLString: String, - parameters: [String: AnyObject]? = nil, - fulfilling progress: Progress? = nil - ) async -> APIResult { - await perform(method, URLString: URLString, parameters: parameters, fulfilling: progress) { - try (JSONSerialization.jsonObject(with: $0) as AnyObject) - } - } - func perform( _ method: HTTPRequestBuilder.Method, URLString: String, @@ -403,8 +392,25 @@ open class WordPressComRestApi: NSObject { return try decoder.decode(type, from: $0) } } +} + +extension WordPressComRESTAPIInterfacing { + + public typealias APIResult = WordPressAPIResult, WordPressComRestApiEndpointError> + + public func perform( + _ method: HTTPRequestBuilder.Method, + URLString: String, + parameters: [String: AnyObject]? = nil, + fulfilling progress: Progress? = nil + ) async -> APIResult { + await perform(method, URLString: URLString, parameters: parameters, fulfilling: progress) { + try (JSONSerialization.jsonObject(with: $0) as AnyObject) + } + } - private func perform( + // FIXME: This was private. It became public during the extraction. Consider whether to make it privated once done. + public func perform( _ method: HTTPRequestBuilder.Method, URLString: String, parameters: [String: AnyObject]?, @@ -434,13 +440,9 @@ open class WordPressComRestApi: NSObject { invalidTokenHandler: invalidTokenHandler ) } -} - -extension WordPressComRESTAPIInterfacing { - - public typealias APIResult = WordPressAPIResult, WordPressComRestApiEndpointError> - func perform( + // FIXME: This was private. It became public during the extraction. Consider whether to make it privated once done. + public func perform( request: HTTPRequestBuilder, fulfilling progress: Progress?, decoder: @escaping (Data) throws -> T, From f9a15a518cf2124739c6ad5b4c85f7f7f9efda2d Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Wed, 10 Apr 2024 09:56:44 +1000 Subject: [PATCH 18/18] Remove a couple of unused variable assignments --- Sources/WordPressKit/Models/RemotePostParameters.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/WordPressKit/Models/RemotePostParameters.swift b/Sources/WordPressKit/Models/RemotePostParameters.swift index f1abb0bb..ea5f6685 100644 --- a/Sources/WordPressKit/Models/RemotePostParameters.swift +++ b/Sources/WordPressKit/Models/RemotePostParameters.swift @@ -236,7 +236,7 @@ public struct RemotePostUpdateParametersWordPressComEncoder: Encodable { try container.encodeIfPresent(parameters.excerpt, forKey: .excerpt) try container.encodeIfPresent(parameters.slug, forKey: .slug) if let value = parameters.featuredImageID { - if let featuredImageID = value { + if value != nil { try container.encode(parameters.featuredImageID, forKey: .featuredImageID) } else { // Passing `null` doesn't work. @@ -340,7 +340,7 @@ public struct RemotePostUpdateParametersXMLRPCEncoder: Encodable { try container.encodeIfPresent(parameters.excerpt, forKey: .excerpt) try container.encodeIfPresent(parameters.slug, forKey: .slug) if let value = parameters.featuredImageID { - if let featuredImageID = value { + if value != nil { try container.encode(parameters.featuredImageID, forKey: .featuredImageID) } else { // Passing `null` doesn't work.