From c57db0459d1a198630dfb7aa72e790be9f301010 Mon Sep 17 00:00:00 2001 From: kean Date: Wed, 10 Apr 2024 17:36:18 -0400 Subject: [PATCH] Add getPost(withID) --- .../Services/PostServiceRemoteExtended.swift | 12 +++-- .../PostServiceRemoteREST+Extended.swift | 20 ++++++-- .../PostServiceRemoteXMLRPC+Extended.swift | 47 ++++++++++--------- .../Services/PostServiceRemoteXMLRPC.h | 2 + .../Services/PostServiceRemoteXMLRPC.m | 12 +++-- 5 files changed, 62 insertions(+), 31 deletions(-) diff --git a/Sources/WordPressKit/Services/PostServiceRemoteExtended.swift b/Sources/WordPressKit/Services/PostServiceRemoteExtended.swift index fb7ed17ec..e12fee489 100644 --- a/Sources/WordPressKit/Services/PostServiceRemoteExtended.swift +++ b/Sources/WordPressKit/Services/PostServiceRemoteExtended.swift @@ -1,23 +1,29 @@ import Foundation public protocol PostServiceRemoteExtended: PostServiceRemote { + /// Returns a post with the given ID. + /// + /// - throws: ``PostServiceRemoteError`` or oher underlying errors + /// (see ``WordPressAPIError``) + func getPost(withID postID: Int) async throws -> RemotePost + /// 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 + /// - throws: ``PostServiceRemoteError`` 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 + /// - throws: ``PostServiceRemoteError`` or oher underlying errors /// (see ``WordPressAPIError``) func deletePost(withID postID: Int) async throws } -public enum PostServiceRemoteUpdatePostError: Error { +public enum PostServiceRemoteError: Error { /// 409 (Conflict) case conflict /// 404 (Not Found) diff --git a/Sources/WordPressKit/Services/PostServiceRemoteREST+Extended.swift b/Sources/WordPressKit/Services/PostServiceRemoteREST+Extended.swift index 6637a7850..af4b0290b 100644 --- a/Sources/WordPressKit/Services/PostServiceRemoteREST+Extended.swift +++ b/Sources/WordPressKit/Services/PostServiceRemoteREST+Extended.swift @@ -1,6 +1,20 @@ import Foundation extension PostServiceRemoteREST: PostServiceRemoteExtended { + public func getPost(withID postID: Int) async throws -> RemotePost { + let path = self.path(forEndpoint: "sites/\(siteID)/posts/\(postID)?context=edit", withVersion: ._1_1) + let result = await wordPressComRestApi.perform(.post, URLString: path) + switch result { + case .success(let response): + return try await decodePost(from: response.body) + case .failure(let error): + if case .endpointError(let error) = error, error.apiErrorCode == "unknown_post" { + throw PostServiceRemoteError.notFound + } + throw error + } + } + 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)) @@ -22,8 +36,8 @@ extension PostServiceRemoteREST: PostServiceRemoteExtended { throw error } switch error.apiErrorCode ?? "" { - case "unknown_post": throw PostServiceRemoteUpdatePostError.notFound - case "old-revision": throw PostServiceRemoteUpdatePostError.conflict + case "unknown_post": throw PostServiceRemoteError.notFound + case "old-revision": throw PostServiceRemoteError.conflict default: throw error } } @@ -40,7 +54,7 @@ extension PostServiceRemoteREST: PostServiceRemoteExtended { throw error } switch error.apiErrorCode ?? "" { - case "unknown_post": throw PostServiceRemoteUpdatePostError.notFound + case "unknown_post": throw PostServiceRemoteError.notFound default: throw error } } diff --git a/Sources/WordPressKit/Services/PostServiceRemoteXMLRPC+Extended.swift b/Sources/WordPressKit/Services/PostServiceRemoteXMLRPC+Extended.swift index b1bccf1a8..4efd438ee 100644 --- a/Sources/WordPressKit/Services/PostServiceRemoteXMLRPC+Extended.swift +++ b/Sources/WordPressKit/Services/PostServiceRemoteXMLRPC+Extended.swift @@ -2,6 +2,20 @@ import Foundation import wpxmlrpc extension PostServiceRemoteXMLRPC: PostServiceRemoteExtended { + public func getPost(withID postID: Int) async throws -> RemotePost { + let parameters = xmlrpcArguments(withExtra: postID) as [AnyObject] + let result = await api.call(method: "wp.getPost", parameters: parameters) + switch result { + case .success(let response): + return try await decodePost(from: response.body) + case .failure(let error): + if case .endpointError(let error) = error, error.code == 404 { + throw PostServiceRemoteError.notFound + } + throw error + } + } + public func createPost(with parameters: RemotePostCreateParameters) async throws -> RemotePost { let dictionary = try makeParameters(from: RemotePostCreateParametersXMLRPCEncoder(parameters: parameters)) let parameters = xmlrpcArguments(withExtra: dictionary) as [AnyObject] @@ -9,7 +23,7 @@ extension PostServiceRemoteXMLRPC: PostServiceRemoteExtended { guard let postID = (response.body as? NSObject)?.numericValue() else { throw URLError(.unknown) // Should never happen } - return try await getPost(withID: postID) + return try await getPost(withID: postID.intValue) } public func patchPost(withID postID: Int, parameters: RemotePostUpdateParameters) async throws -> RemotePost { @@ -21,14 +35,14 @@ extension PostServiceRemoteXMLRPC: PostServiceRemoteExtended { let result = await api.call(method: "metaWeblog.editPost", parameters: parameters) switch result { case .success: - return try await getPost(withID: postID as NSNumber) + return try await getPost(withID: postID) 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 + case 404: throw PostServiceRemoteError.notFound + case 409: throw PostServiceRemoteError.conflict default: throw error } } @@ -41,28 +55,19 @@ extension PostServiceRemoteXMLRPC: PostServiceRemoteExtended { 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 + if case .endpointError(let error) = error, error.code == 404 { + throw PostServiceRemoteError.notFound } + 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 decodePost(from object: AnyObject) async throws -> RemotePost { + guard let dictionary = object as? [AnyHashable: Any] else { + throw WordPressAPIError.unparsableResponse(response: nil, body: nil) } + return PostServiceRemoteXMLRPC.remotePost(fromXMLRPCDictionary: dictionary) } private func makeParameters(from value: T) throws -> [String: AnyObject] { diff --git a/Sources/WordPressKit/Services/PostServiceRemoteXMLRPC.h b/Sources/WordPressKit/Services/PostServiceRemoteXMLRPC.h index d0ceb882c..897863850 100644 --- a/Sources/WordPressKit/Services/PostServiceRemoteXMLRPC.h +++ b/Sources/WordPressKit/Services/PostServiceRemoteXMLRPC.h @@ -4,4 +4,6 @@ @interface PostServiceRemoteXMLRPC : ServiceRemoteWordPressXMLRPC ++ (RemotePost *)remotePostFromXMLRPCDictionary:(NSDictionary *)xmlrpcDictionary; + @end diff --git a/Sources/WordPressKit/Services/PostServiceRemoteXMLRPC.m b/Sources/WordPressKit/Services/PostServiceRemoteXMLRPC.m index 967d02362..e5454bc82 100644 --- a/Sources/WordPressKit/Services/PostServiceRemoteXMLRPC.m +++ b/Sources/WordPressKit/Services/PostServiceRemoteXMLRPC.m @@ -294,6 +294,10 @@ - (NSDictionary *)dictionaryWithRemoteOptions:(id )opt } - (RemotePost *)remotePostFromXMLRPCDictionary:(NSDictionary *)xmlrpcDictionary { + return [PostServiceRemoteXMLRPC remotePostFromXMLRPCDictionary:xmlrpcDictionary]; +} + ++ (RemotePost *)remotePostFromXMLRPCDictionary:(NSDictionary *)xmlrpcDictionary { RemotePost *post = [RemotePost new]; post.postID = [xmlrpcDictionary numberForKey:@"post_id"]; @@ -339,7 +343,7 @@ - (RemotePost *)remotePostFromXMLRPCDictionary:(NSDictionary *)xmlrpcDictionary return post; } -- (NSString *)statusForPostStatus:(NSString *)status andDate:(NSDate *)date ++ (NSString *)statusForPostStatus:(NSString *)status andDate:(NSDate *)date { // Scheduled posts are synced with a post_status of 'publish' but we want to // work with a status of 'future' from within the app. @@ -349,12 +353,12 @@ - (NSString *)statusForPostStatus:(NSString *)status andDate:(NSDate *)date return status; } -- (NSArray *)tagsFromXMLRPCTermsArray:(NSArray *)terms { ++ (NSArray *)tagsFromXMLRPCTermsArray:(NSArray *)terms { NSArray *tags = [terms filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"taxonomy = 'post_tag' AND name != NIL"]]; return [tags valueForKey:@"name"]; } -- (NSArray *)remoteCategoriesFromXMLRPCTermsArray:(NSArray *)terms { ++ (NSArray *)remoteCategoriesFromXMLRPCTermsArray:(NSArray *)terms { return [[terms wp_filter:^BOOL(NSDictionary *category) { return [[category stringForKey:@"taxonomy"] isEqualToString:@"category"]; }] wp_map:^id(NSDictionary *category) { @@ -362,7 +366,7 @@ - (NSArray *)remoteCategoriesFromXMLRPCTermsArray:(NSArray *)terms { }]; } -- (RemotePostCategory *)remoteCategoryFromXMLRPCDictionary:(NSDictionary *)xmlrpcCategory { ++ (RemotePostCategory *)remoteCategoryFromXMLRPCDictionary:(NSDictionary *)xmlrpcCategory { RemotePostCategory *category = [RemotePostCategory new]; category.categoryID = [xmlrpcCategory numberForKey:@"term_id"]; category.name = [xmlrpcCategory stringForKey:@"name"];