Skip to content
This repository was archived by the owner on Sep 15, 2025. It is now read-only.

Commit 9ab4b43

Browse files
committed
Add RemotePostCreateParameters
1 parent 32840bd commit 9ab4b43

File tree

4 files changed

+258
-53
lines changed

4 files changed

+258
-53
lines changed
Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import Foundation
22

33
public protocol PostServiceRemoteExtended: PostServiceRemote {
4-
/// Performs a partial update of the given post.
4+
/// Creates a new post with the given parameters.
5+
func createPost(with parameters: RemotePostCreateParameters) async throws -> RemotePost
6+
7+
/// Performs a partial update to the existing post.
58
func patchPost(withID postID: Int, changes: RemotePostUpdateParameters) async throws -> RemotePost
69
}
Lines changed: 34 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,66 +1,51 @@
11
import Foundation
22

33
extension PostServiceRemoteREST: PostServiceRemoteExtended {
4-
public func patchPost(withID postID: Int, changes: RemotePostUpdateParameters) async throws -> RemotePost {
5-
let path = self.path(forEndpoint: "sites/\(siteID)/posts/\(postID)?context=edit", withVersion: ._1_2)
6-
let parameters = RemotePostUpdateParametersWordPressComEncoder.makeParameters(for: changes)
4+
public func createPost(with parameters: RemotePostCreateParameters) async throws -> RemotePost {
5+
let path = self.path(forEndpoint: "sites/\(siteID)/posts/new?context=edit", withVersion: ._1_2)
6+
let parameters = try makeParameters(from: RemotePostCreateParametersWordPressComEncoder(parameters: parameters))
77

8-
return try await withUnsafeThrowingContinuation { continuation in
9-
wordPressComRestApi.POST(path, parameters: parameters) { responseObject, _ in
10-
if let dictionary = responseObject as? [AnyHashable: Any],
11-
let post = PostServiceRemoteREST.remotePost(fromJSONDictionary: dictionary) {
12-
continuation.resume(returning: post)
13-
} else {
14-
continuation.resume(throwing: URLError(.unknown)) // Should never happen
15-
}
8+
let response = try await withUnsafeThrowingContinuation { continuation in
9+
wordPressComRestApi.POST(path, parameters: parameters) { object, _ in
10+
continuation.resume(returning: object)
1611
} failure: { error, _ in
1712
continuation.resume(throwing: error)
1813
}
1914
}
15+
return try await decodePost(from: response)
2016
}
21-
}
2217

23-
private struct RemotePostUpdateParametersWordPressComEncoder: Encodable {
24-
let parameters: RemotePostUpdateParameters
18+
public func patchPost(withID postID: Int, changes: RemotePostUpdateParameters) async throws -> RemotePost {
19+
let path = self.path(forEndpoint: "sites/\(siteID)/posts/\(postID)?context=edit", withVersion: ._1_2)
20+
let parameters = try makeParameters(from: RemotePostUpdateParametersWordPressComEncoder(parameters: changes))
2521

26-
static func makeParameters(for parameters: RemotePostUpdateParameters) -> [String: AnyObject]? {
27-
let encoder = JSONEncoder()
28-
encoder.dateEncodingStrategy = .formatted(NSDate.rfc3339DateFormatter())
29-
guard let data = try? encoder.encode(RemotePostUpdateParametersWordPressComEncoder(parameters: parameters)),
30-
let object = try? JSONSerialization.jsonObject(with: data) else {
31-
return nil // Should never happen
22+
let response = try await withUnsafeThrowingContinuation { continuation in
23+
wordPressComRestApi.POST(path, parameters: parameters) { object, _ in
24+
continuation.resume(returning: object)
25+
} failure: { error, _ in
26+
continuation.resume(throwing: error)
27+
}
3228
}
33-
return object as? [String: AnyObject]
29+
return try await decodePost(from: response)
3430
}
31+
}
3532

36-
func encode(to encoder: Encoder) throws {
37-
var container = encoder.container(keyedBy: StringCodingKey.self)
38-
try container.encodeIfPresent(parameters.ifNotModifiedSince, forKey: "if_not_modified_since")
39-
try container.encodeIfPresent(parameters.status, forKey: "status")
40-
try container.encodeIfPresent(parameters.date, forKey: "date")
41-
try container.encodeIfPresent(parameters.authorID, forKey: "author")
42-
try container.encodeIfPresent(parameters.title, forKey: "title")
43-
try container.encodeIfPresent(parameters.content, forKey: "content")
44-
try container.encodeIfPresent(parameters.password, forKey: "password")
45-
try container.encodeIfPresent(parameters.excerpt, forKey: "excerpt")
46-
try container.encodeIfPresent(parameters.slug, forKey: "slug")
47-
try container.encodeIfPresent(parameters.featuredImageID, forKey: "featured_image")
48-
49-
// Pages
50-
if let parentPageID = parameters.parentPageID {
51-
try container.encodeIfPresent(parentPageID, forKey: "parent")
52-
}
33+
// Decodes the post in the background.
34+
private func decodePost(from object: AnyObject) async throws -> RemotePost {
35+
guard let dictionary = object as? [AnyHashable: Any],
36+
let post = PostServiceRemoteREST.remotePost(fromJSONDictionary: dictionary) else {
37+
throw WordPressAPIError<WordPressComRestApiEndpointError>.unparsableResponse(response: nil, body: nil)
38+
}
39+
return post
40+
}
5341

54-
// Posts
55-
try container.encodeIfPresent(parameters.format, forKey: "format")
56-
if let tags = parameters.tags {
57-
try container.encode([
58-
"terms": [
59-
"post_tag": tags
60-
]
61-
], forKey: "terms")
62-
}
63-
try container.encodeIfPresent(parameters.categoryIDs, forKey: "categories_by_id")
64-
try container.encodeIfPresent(parameters.isSticky, forKey: "sticky")
42+
private func makeParameters<T: Encodable>(from value: T) throws -> [String: AnyObject] {
43+
let encoder = JSONEncoder()
44+
encoder.dateEncodingStrategy = .formatted(NSDate.rfc3339DateFormatter())
45+
let data = try encoder.encode(value)
46+
let object = try JSONSerialization.jsonObject(with: data)
47+
guard let dictionary = object as? [String: AnyObject] else {
48+
throw URLError(.unknown) // This should never happen
6549
}
50+
return dictionary
6651
}

WordPressKit/PostServiceRemoteXMLRPC+Extended.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import Foundation
22

33
extension PostServiceRemoteXMLRPC: PostServiceRemoteExtended {
4+
public func createPost(with parameters: RemotePostCreateParameters) async throws -> RemotePost {
5+
throw URLError(.unknown, userInfo: [NSLocalizedFailureErrorKey: "Unimplemented"])
6+
}
7+
48
public func patchPost(withID postID: Int, changes: RemotePostUpdateParameters) async throws -> RemotePost {
59
throw URLError(.unknown, userInfo: [NSLocalizedFailureErrorKey: "Unimplemented"])
610
}

WordPressKit/RemotePostParameters.swift

Lines changed: 216 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,37 @@
11
import Foundation
22

3-
/// Represents a partial update to be applied to a post.
3+
/// The parameters required to create a post or a page.
4+
public struct RemotePostCreateParameters {
5+
public var status: String
6+
public var date: Date?
7+
public var authorID: Int?
8+
public var title: String?
9+
public var content: String?
10+
public var password: String?
11+
public var excerpt: String?
12+
public var slug: String?
13+
public var featuredImageID: Int?
14+
15+
// Pages
16+
public var parentPageID: Int?
17+
18+
// Posts
19+
public var format: String?
20+
public var isSticky = false
21+
public var tags: [String] = []
22+
public var categoryIDs: [Int] = []
23+
24+
public init(status: String) {
25+
self.status = status
26+
}
27+
}
28+
29+
/// Represents a partial update to be applied to a post or a page.
430
public struct RemotePostUpdateParameters {
531
public var ifNotModifiedSince: Date?
632

733
public var status: String?
8-
public var date: Date?
34+
public var date: Date??
935
public var authorID: Int??
1036
public var title: String??
1137
public var content: String??
@@ -19,9 +45,196 @@ public struct RemotePostUpdateParameters {
1945

2046
// Posts
2147
public var format: String??
48+
public var isSticky: Bool?
2249
public var tags: [String]?
2350
public var categoryIDs: [Int]?
24-
public var isSticky: Bool?
2551

2652
public init() {}
2753
}
54+
55+
// MARK: - Diff
56+
57+
extension RemotePostCreateParameters {
58+
/// Returns a diff required to update from the `previous` to the current
59+
/// version of the post.
60+
public func changes(from previous: RemotePostCreateParameters) -> RemotePostUpdateParameters {
61+
var changes = RemotePostUpdateParameters()
62+
if previous.status != status {
63+
changes.status = status
64+
}
65+
if previous.date != date {
66+
changes.date = date
67+
}
68+
if previous.authorID != authorID {
69+
changes.authorID = authorID
70+
}
71+
if previous.title != title {
72+
changes.title = title
73+
}
74+
if previous.content != content {
75+
changes.content = content
76+
}
77+
if previous.password != password {
78+
changes.password = password
79+
}
80+
if previous.excerpt != excerpt {
81+
changes.excerpt = excerpt
82+
}
83+
if previous.slug != slug {
84+
changes.slug = slug
85+
}
86+
if previous.featuredImageID != featuredImageID {
87+
changes.featuredImageID = featuredImageID
88+
}
89+
if previous.parentPageID != parentPageID {
90+
changes.parentPageID = parentPageID
91+
}
92+
if previous.format != format {
93+
changes.format = format
94+
}
95+
if previous.isSticky != isSticky {
96+
changes.isSticky = isSticky
97+
}
98+
if previous.tags != tags {
99+
changes.tags = tags
100+
}
101+
if previous.categoryIDs != categoryIDs {
102+
changes.categoryIDs = categoryIDs
103+
}
104+
return changes
105+
}
106+
107+
/// Applies the diff to the receiver.
108+
public mutating func apply(_ changes: RemotePostUpdateParameters) {
109+
if let status = changes.status {
110+
self.status = status
111+
}
112+
if let date = changes.date {
113+
self.date = date
114+
}
115+
if let authorID = changes.authorID {
116+
self.authorID = authorID
117+
}
118+
if let title = changes.title {
119+
self.title = title
120+
}
121+
if let content = changes.content {
122+
self.content = content
123+
}
124+
if let password = changes.password {
125+
self.password = password
126+
}
127+
if let excerpt = changes.excerpt {
128+
self.excerpt = excerpt
129+
}
130+
if let slug = changes.slug {
131+
self.slug = slug
132+
}
133+
if let featuredImageID = changes.featuredImageID {
134+
self.featuredImageID = featuredImageID
135+
}
136+
if let parentPageID = changes.parentPageID {
137+
self.parentPageID = parentPageID
138+
}
139+
if let format = changes.format {
140+
self.format = format
141+
}
142+
if let isSticky = changes.isSticky {
143+
self.isSticky = isSticky
144+
}
145+
if let tags = changes.tags {
146+
self.tags = tags
147+
}
148+
if let categoryIDs = changes.categoryIDs {
149+
self.categoryIDs = categoryIDs
150+
}
151+
}
152+
}
153+
154+
// MARK: - Encoding
155+
156+
private enum RemotePostCodingKeys: String, CodingKey {
157+
case ifNotModifiedSince = "if_not_modified_since"
158+
case status
159+
case date
160+
case authorID = "author"
161+
case title
162+
case content
163+
case password
164+
case excerpt
165+
case slug
166+
case featuredImageID = "featured_image"
167+
case parentPageID = "parent"
168+
case terms
169+
case format
170+
case isSticky = "sticky"
171+
case categoryIDs = "categories_by_id"
172+
173+
static let postTags = "post_tag"
174+
}
175+
176+
struct RemotePostCreateParametersWordPressComEncoder: Encodable {
177+
let parameters: RemotePostCreateParameters
178+
179+
func encode(to encoder: Encoder) throws {
180+
var container = encoder.container(keyedBy: RemotePostCodingKeys.self)
181+
try container.encodeIfPresent(parameters.status, forKey: .status)
182+
try container.encodeIfPresent(parameters.date, forKey: .date)
183+
try container.encodeIfPresent(parameters.authorID, forKey: .authorID)
184+
try container.encodeIfPresent(parameters.title, forKey: .title)
185+
try container.encodeIfPresent(parameters.content, forKey: .content)
186+
try container.encodeIfPresent(parameters.password, forKey: .password)
187+
try container.encodeIfPresent(parameters.excerpt, forKey: .excerpt)
188+
try container.encodeIfPresent(parameters.slug, forKey: .slug)
189+
try container.encodeIfPresent(parameters.featuredImageID, forKey: .featuredImageID)
190+
191+
// Pages
192+
if let parentPageID = parameters.parentPageID {
193+
try container.encodeIfPresent(parentPageID, forKey: .parentPageID)
194+
}
195+
196+
// Posts
197+
try container.encodeIfPresent(parameters.format, forKey: .format)
198+
if !parameters.tags.isEmpty {
199+
try container.encode([RemotePostCodingKeys.postTags: parameters.tags], forKey: .terms)
200+
}
201+
if !parameters.categoryIDs.isEmpty {
202+
try container.encodeIfPresent(parameters.categoryIDs, forKey: .categoryIDs)
203+
}
204+
if parameters.isSticky {
205+
try container.encode(parameters.isSticky, forKey: .isSticky)
206+
}
207+
}
208+
}
209+
210+
struct RemotePostUpdateParametersWordPressComEncoder: Encodable {
211+
let parameters: RemotePostUpdateParameters
212+
213+
func encode(to encoder: Encoder) throws {
214+
var container = encoder.container(keyedBy: RemotePostCodingKeys.self)
215+
try container.encodeIfPresent(parameters.ifNotModifiedSince, forKey: .ifNotModifiedSince)
216+
217+
try container.encodeIfPresent(parameters.status, forKey: .status)
218+
try container.encodeIfPresent(parameters.date, forKey: .date)
219+
try container.encodeIfPresent(parameters.authorID, forKey: .authorID)
220+
try container.encodeIfPresent(parameters.title, forKey: .title)
221+
try container.encodeIfPresent(parameters.content, forKey: .content)
222+
try container.encodeIfPresent(parameters.password, forKey: .password)
223+
try container.encodeIfPresent(parameters.excerpt, forKey: .excerpt)
224+
try container.encodeIfPresent(parameters.slug, forKey: .slug)
225+
try container.encodeIfPresent(parameters.featuredImageID, forKey: .featuredImageID)
226+
227+
// Pages
228+
if let parentPageID = parameters.parentPageID {
229+
try container.encodeIfPresent(parentPageID, forKey: .parentPageID)
230+
}
231+
232+
// Posts
233+
try container.encodeIfPresent(parameters.format, forKey: .format)
234+
if let tags = parameters.tags {
235+
try container.encode([RemotePostCodingKeys.postTags: tags], forKey: .terms)
236+
}
237+
try container.encodeIfPresent(parameters.categoryIDs, forKey: .categoryIDs)
238+
try container.encodeIfPresent(parameters.isSticky, forKey: .isSticky)
239+
}
240+
}

0 commit comments

Comments
 (0)