From 3c190711e32672456608ecf7ff468889d2118cf7 Mon Sep 17 00:00:00 2001 From: Paul Von Schrottky Date: Sun, 27 Oct 2019 01:13:04 -0300 Subject: [PATCH 01/13] Add post autosave metadata support to REST API Autosave metadata is supported through the new `meta` option when fetching posts. Autosave metadata currently supported are: `title`, `excerpt`, and `content`. --- WordPressKit/PostServiceRemoteOptions.h | 6 ++++++ WordPressKit/PostServiceRemoteREST.m | 11 +++++++++++ WordPressKit/RemotePost.h | 3 +++ 3 files changed, 20 insertions(+) diff --git a/WordPressKit/PostServiceRemoteOptions.h b/WordPressKit/PostServiceRemoteOptions.h index 3c33a82a..ac2e3d0d 100644 --- a/WordPressKit/PostServiceRemoteOptions.h +++ b/WordPressKit/PostServiceRemoteOptions.h @@ -72,4 +72,10 @@ typedef NS_ENUM(NSUInteger, PostServiceResultsOrdering) { */ - (NSString *)search; +/** + The metadata to include in the returned results. + @attention Not supported in XML-RPC. + */ +- (NSString *)meta; + @end diff --git a/WordPressKit/PostServiceRemoteREST.m b/WordPressKit/PostServiceRemoteREST.m index f4b50e48..e371bfc6 100644 --- a/WordPressKit/PostServiceRemoteREST.m +++ b/WordPressKit/PostServiceRemoteREST.m @@ -15,6 +15,7 @@ static NSString * const RemoteOptionKeyStatus = @"status"; static NSString * const RemoteOptionKeySearch = @"search"; static NSString * const RemoteOptionKeyAuthor = @"author"; +static NSString * const RemoteOptionKeyMeta = @"meta"; static NSString * const RemoteOptionValueOrderAscending = @"ASC"; static NSString * const RemoteOptionValueOrderDescending = @"DESC"; @@ -365,6 +366,9 @@ - (NSDictionary *)dictionaryWithRemoteOptions:(id )opt if (options.search.length > 0) { [remoteParams setObject:options.search forKey:RemoteOptionKeySearch]; } + if (options.meta.length > 0) { + [remoteParams setObject:options.meta forKey:RemoteOptionKeyMeta]; + } return remoteParams.count ? [NSDictionary dictionaryWithDictionary:remoteParams] : nil; } @@ -432,6 +436,13 @@ - (RemotePost *)remotePostFromJSONDictionary:(NSDictionary *)jsonPost { post.tags = [self tagNamesFromJSONDictionary:jsonPost[@"tags"]]; post.revisions = [jsonPost arrayForKey:@"revisions"]; + + NSDictionary *autosave = jsonPost[@"meta"][@"data"][@"autosave"]; + if (autosave) { + post.autosaveTitle = autosave[@"title"]; + post.autosaveContent = autosave[@"content"]; + post.autosaveExcerpt = autosave[@"excerpt"]; + } // Pick an image to use for display if (post.postThumbnailPath) { diff --git a/WordPressKit/RemotePost.h b/WordPressKit/RemotePost.h index 98c37e0f..44a66fd5 100644 --- a/WordPressKit/RemotePost.h +++ b/WordPressKit/RemotePost.h @@ -34,6 +34,9 @@ extern NSString * const PostStatusDeleted; @property (nonatomic, strong) NSString *postThumbnailPath; @property (nonatomic, strong) NSString *type; @property (nonatomic, strong) NSString *format; +@property (nonatomic, copy, nullable) NSString *autosaveTitle; +@property (nonatomic, copy, nullable) NSString *autosaveContent; +@property (nonatomic, copy, nullable) NSString *autosaveExcerpt; @property (nonatomic, strong) NSNumber *commentCount; @property (nonatomic, strong) NSNumber *likeCount; From a488bf1aca9f2ebf446c9dd0ae5aabd0660b7a7f Mon Sep 17 00:00:00 2001 From: Paul Von Schrottky Date: Sun, 27 Oct 2019 14:53:14 -0300 Subject: [PATCH 02/13] Cleanly handle NSNull when fetching autosave data Simplify the treatment of null values when creating a `RemotePost` from a dictionary representing its JSON data. --- WordPressKit/PostServiceRemoteREST.m | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/WordPressKit/PostServiceRemoteREST.m b/WordPressKit/PostServiceRemoteREST.m index e371bfc6..448875fd 100644 --- a/WordPressKit/PostServiceRemoteREST.m +++ b/WordPressKit/PostServiceRemoteREST.m @@ -438,11 +438,9 @@ - (RemotePost *)remotePostFromJSONDictionary:(NSDictionary *)jsonPost { post.revisions = [jsonPost arrayForKey:@"revisions"]; NSDictionary *autosave = jsonPost[@"meta"][@"data"][@"autosave"]; - if (autosave) { - post.autosaveTitle = autosave[@"title"]; - post.autosaveContent = autosave[@"content"]; - post.autosaveExcerpt = autosave[@"excerpt"]; - } + post.autosaveTitle = autosave[@"title"]; + post.autosaveContent = autosave[@"content"]; + post.autosaveExcerpt = autosave[@"excerpt"]; // Pick an image to use for display if (post.postThumbnailPath) { From ae640e255203dc87c0111c3d8128661da7e948b5 Mon Sep 17 00:00:00 2001 From: Paul Von Schrottky Date: Sun, 27 Oct 2019 16:11:44 -0300 Subject: [PATCH 03/13] Add autosave modified date to `RemotePost` --- WordPressKit/PostServiceRemoteREST.m | 1 + WordPressKit/RemotePost.h | 1 + 2 files changed, 2 insertions(+) diff --git a/WordPressKit/PostServiceRemoteREST.m b/WordPressKit/PostServiceRemoteREST.m index 448875fd..bd9209db 100644 --- a/WordPressKit/PostServiceRemoteREST.m +++ b/WordPressKit/PostServiceRemoteREST.m @@ -441,6 +441,7 @@ - (RemotePost *)remotePostFromJSONDictionary:(NSDictionary *)jsonPost { post.autosaveTitle = autosave[@"title"]; post.autosaveContent = autosave[@"content"]; post.autosaveExcerpt = autosave[@"excerpt"]; + post.autosaveModifiedDate = autosave[@"modified"]; // Pick an image to use for display if (post.postThumbnailPath) { diff --git a/WordPressKit/RemotePost.h b/WordPressKit/RemotePost.h index 44a66fd5..7a90ffb6 100644 --- a/WordPressKit/RemotePost.h +++ b/WordPressKit/RemotePost.h @@ -37,6 +37,7 @@ extern NSString * const PostStatusDeleted; @property (nonatomic, copy, nullable) NSString *autosaveTitle; @property (nonatomic, copy, nullable) NSString *autosaveContent; @property (nonatomic, copy, nullable) NSString *autosaveExcerpt; +@property (nonatomic, copy, nullable) NSDate *autosaveModifiedDate; @property (nonatomic, strong) NSNumber *commentCount; @property (nonatomic, strong) NSNumber *likeCount; From ae89a866415bf767772bc9b3db4ca460b501a9f2 Mon Sep 17 00:00:00 2001 From: Paul Von Schrottky Date: Sun, 27 Oct 2019 17:19:57 -0300 Subject: [PATCH 04/13] Remove unsupported claim about meta parameter I'm unsure if `meta` is supported in XML-RPC, so removing this comment. --- WordPressKit/PostServiceRemoteOptions.h | 1 - 1 file changed, 1 deletion(-) diff --git a/WordPressKit/PostServiceRemoteOptions.h b/WordPressKit/PostServiceRemoteOptions.h index ac2e3d0d..d568b204 100644 --- a/WordPressKit/PostServiceRemoteOptions.h +++ b/WordPressKit/PostServiceRemoteOptions.h @@ -74,7 +74,6 @@ typedef NS_ENUM(NSUInteger, PostServiceResultsOrdering) { /** The metadata to include in the returned results. - @attention Not supported in XML-RPC. */ - (NSString *)meta; From c90227b7cd28623feda3c77ef8d420d242c5feec Mon Sep 17 00:00:00 2001 From: Paul Von Schrottky Date: Sun, 27 Oct 2019 17:58:25 -0300 Subject: [PATCH 05/13] Remove nullable from autosave properties Although a good idea, specifying `nullable` triggers warnings on the other properties of this class. To resolve the warnings we would have to either explicitly annotate each property as nullable or nonnull - or, if all properties are not nullable, mark the class with NS_ASSUME_NONNULL_BEGIN. --- WordPressKit/RemotePost.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/WordPressKit/RemotePost.h b/WordPressKit/RemotePost.h index 7a90ffb6..aed6f3cd 100644 --- a/WordPressKit/RemotePost.h +++ b/WordPressKit/RemotePost.h @@ -34,10 +34,10 @@ extern NSString * const PostStatusDeleted; @property (nonatomic, strong) NSString *postThumbnailPath; @property (nonatomic, strong) NSString *type; @property (nonatomic, strong) NSString *format; -@property (nonatomic, copy, nullable) NSString *autosaveTitle; -@property (nonatomic, copy, nullable) NSString *autosaveContent; -@property (nonatomic, copy, nullable) NSString *autosaveExcerpt; -@property (nonatomic, copy, nullable) NSDate *autosaveModifiedDate; +@property (nonatomic, copy) NSString *autosaveTitle; +@property (nonatomic, copy) NSString *autosaveContent; +@property (nonatomic, copy) NSString *autosaveExcerpt; +@property (nonatomic, copy) NSDate *autosaveModifiedDate; @property (nonatomic, strong) NSNumber *commentCount; @property (nonatomic, strong) NSNumber *likeCount; From 96af321bf1ce549b364a4b9c28d06242b18d52ee Mon Sep 17 00:00:00 2001 From: Paul Von Schrottky Date: Sun, 27 Oct 2019 21:00:46 -0300 Subject: [PATCH 06/13] Deseralize autosave modified date from string --- WordPressKit/PostServiceRemoteREST.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/WordPressKit/PostServiceRemoteREST.m b/WordPressKit/PostServiceRemoteREST.m index bd9209db..9ed6968b 100644 --- a/WordPressKit/PostServiceRemoteREST.m +++ b/WordPressKit/PostServiceRemoteREST.m @@ -441,8 +441,8 @@ - (RemotePost *)remotePostFromJSONDictionary:(NSDictionary *)jsonPost { post.autosaveTitle = autosave[@"title"]; post.autosaveContent = autosave[@"content"]; post.autosaveExcerpt = autosave[@"excerpt"]; - post.autosaveModifiedDate = autosave[@"modified"]; - + post.autosaveModifiedDate = [NSDate dateWithWordPressComJSONString:autosave[@"modified"]]; + // Pick an image to use for display if (post.postThumbnailPath) { post.pathForDisplayImage = post.postThumbnailPath; From 03f9667d5f1cf5bb17ebc6b14f1e0218cecf573f Mon Sep 17 00:00:00 2001 From: Paul Von Schrottky Date: Thu, 31 Oct 2019 23:42:26 -0300 Subject: [PATCH 07/13] Add additional autosave attributes to RemotePost --- WordPressKit.xcodeproj/project.pbxproj | 4 ++++ WordPressKit/PostServiceRemoteREST.m | 18 +++++++++++++----- WordPressKit/RemotePost.h | 7 ++----- WordPressKit/RemotePostAutosave.swift | 13 +++++++++++++ 4 files changed, 32 insertions(+), 10 deletions(-) create mode 100644 WordPressKit/RemotePostAutosave.swift diff --git a/WordPressKit.xcodeproj/project.pbxproj b/WordPressKit.xcodeproj/project.pbxproj index fdf70310..d608fa21 100644 --- a/WordPressKit.xcodeproj/project.pbxproj +++ b/WordPressKit.xcodeproj/project.pbxproj @@ -17,6 +17,7 @@ 17CE77F420C701C8001DEA5A /* ReaderSiteSearchServiceRemoteTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17CE77F320C701C8001DEA5A /* ReaderSiteSearchServiceRemoteTests.swift */; }; 1A4F98672279A87D00D86E8E /* WPKit-Swift.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A4F98662279A87D00D86E8E /* WPKit-Swift.h */; settings = {ATTRIBUTES = (Private, ); }; }; 240315B0A1D6C2B981572B5B /* Pods_WordPressKitTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ED05C8FF3E61D93CE5BA527E /* Pods_WordPressKitTests.framework */; }; + 32E1DD23236AA09A008914B0 /* RemotePostAutosave.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32E1DD22236AA09A008914B0 /* RemotePostAutosave.swift */; }; 40247DFA2120D8E100AE1C3C /* AutomatedTransferService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40247DF92120D8E100AE1C3C /* AutomatedTransferService.swift */; }; 40247DFC2120E69600AE1C3C /* AutomatedTransferStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40247DFB2120E69600AE1C3C /* AutomatedTransferStatus.swift */; }; 404057C5221B30400060250C /* StatsSearchTermTimeIntervalData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 404057C4221B30400060250C /* StatsSearchTermTimeIntervalData.swift */; }; @@ -535,6 +536,7 @@ 17CE77F320C701C8001DEA5A /* ReaderSiteSearchServiceRemoteTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderSiteSearchServiceRemoteTests.swift; sourceTree = ""; }; 1A4F98662279A87D00D86E8E /* WPKit-Swift.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "WPKit-Swift.h"; sourceTree = ""; }; 264F5C834541BBF2018F4964 /* Pods-WordPressKitTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WordPressKitTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-WordPressKitTests/Pods-WordPressKitTests.debug.xcconfig"; sourceTree = ""; }; + 32E1DD22236AA09A008914B0 /* RemotePostAutosave.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemotePostAutosave.swift; sourceTree = ""; }; 40247DF92120D8E100AE1C3C /* AutomatedTransferService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutomatedTransferService.swift; sourceTree = ""; }; 40247DFB2120E69600AE1C3C /* AutomatedTransferStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutomatedTransferStatus.swift; sourceTree = ""; }; 404057C4221B30400060250C /* StatsSearchTermTimeIntervalData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatsSearchTermTimeIntervalData.swift; sourceTree = ""; }; @@ -1571,6 +1573,7 @@ E1D6B555200E46F200325669 /* WPTimeZone.swift */, E632D7771F6E047400297F6D /* SocialLogin2FANonceInfo.swift */, 17CE77F020C6EB41001DEA5A /* ReaderFeed.swift */, + 32E1DD22236AA09A008914B0 /* RemotePostAutosave.swift */, ); name = Models; sourceTree = ""; @@ -2392,6 +2395,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 32E1DD23236AA09A008914B0 /* RemotePostAutosave.swift in Sources */, 9368C7B41EC630270092CE8E /* StatsItemAction.m in Sources */, 7430C9B41F1927C50051B8E6 /* RemoteReaderSite.m in Sources */, 74585B8E1F0D51A100E7E667 /* DomainsServiceRemote.swift in Sources */, diff --git a/WordPressKit/PostServiceRemoteREST.m b/WordPressKit/PostServiceRemoteREST.m index 9ed6968b..500351b2 100644 --- a/WordPressKit/PostServiceRemoteREST.m +++ b/WordPressKit/PostServiceRemoteREST.m @@ -437,11 +437,19 @@ - (RemotePost *)remotePostFromJSONDictionary:(NSDictionary *)jsonPost { post.revisions = [jsonPost arrayForKey:@"revisions"]; - NSDictionary *autosave = jsonPost[@"meta"][@"data"][@"autosave"]; - post.autosaveTitle = autosave[@"title"]; - post.autosaveContent = autosave[@"content"]; - post.autosaveExcerpt = autosave[@"excerpt"]; - post.autosaveModifiedDate = [NSDate dateWithWordPressComJSONString:autosave[@"modified"]]; + NSDictionary *autosaveAttributes = jsonPost[@"meta"][@"data"][@"autosave"]; + if (autosaveAttributes) { + RemotePostAutosave *autosave = [[RemotePostAutosave alloc] init]; + autosave.title = autosaveAttributes[@"title"]; + autosave.content = autosaveAttributes[@"content"]; + autosave.excerpt = autosaveAttributes[@"excerpt"]; + autosave.modifiedDate = [NSDate dateWithWordPressComJSONString:autosaveAttributes[@"modified"]]; + autosave.identifier = autosaveAttributes[@"ID"]; + autosave.authorID = autosaveAttributes[@"author_ID"]; + autosave.postID = autosaveAttributes[@"post_ID"]; + autosave.previewURL = autosaveAttributes[@"preview_URL"]; + post.autosave = autosave; + } // Pick an image to use for display if (post.postThumbnailPath) { diff --git a/WordPressKit/RemotePost.h b/WordPressKit/RemotePost.h index aed6f3cd..a03ad8c4 100644 --- a/WordPressKit/RemotePost.h +++ b/WordPressKit/RemotePost.h @@ -1,4 +1,5 @@ #import +@class RemotePostAutosave; extern NSString * const PostStatusDraft; extern NSString * const PostStatusPending; @@ -34,11 +35,7 @@ extern NSString * const PostStatusDeleted; @property (nonatomic, strong) NSString *postThumbnailPath; @property (nonatomic, strong) NSString *type; @property (nonatomic, strong) NSString *format; -@property (nonatomic, copy) NSString *autosaveTitle; -@property (nonatomic, copy) NSString *autosaveContent; -@property (nonatomic, copy) NSString *autosaveExcerpt; -@property (nonatomic, copy) NSDate *autosaveModifiedDate; - +@property (nonatomic, strong) RemotePostAutosave *autosave; @property (nonatomic, strong) NSNumber *commentCount; @property (nonatomic, strong) NSNumber *likeCount; diff --git a/WordPressKit/RemotePostAutosave.swift b/WordPressKit/RemotePostAutosave.swift new file mode 100644 index 00000000..02f5b944 --- /dev/null +++ b/WordPressKit/RemotePostAutosave.swift @@ -0,0 +1,13 @@ +import Foundation + +/// Encapsulates the autosave attributes of a post. +@objcMembers class RemotePostAutosave: NSObject { + var title: String? + var excerpt: String? + var content: String? + var modifiedDate: Date? + var identifier: NSNumber? + var authorID: String? + var postID: NSNumber? + var previewURL: String? +} From 85bb8a50c6ffd6de403be4485231b589f03694ce Mon Sep 17 00:00:00 2001 From: Paul Von Schrottky Date: Sat, 2 Nov 2019 14:41:42 -0300 Subject: [PATCH 08/13] Make RemotePostAutosave Obj-C compatible --- WordPressKit/RemotePostAutosave.swift | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/WordPressKit/RemotePostAutosave.swift b/WordPressKit/RemotePostAutosave.swift index 02f5b944..84f01c2e 100644 --- a/WordPressKit/RemotePostAutosave.swift +++ b/WordPressKit/RemotePostAutosave.swift @@ -1,13 +1,15 @@ import Foundation /// Encapsulates the autosave attributes of a post. -@objcMembers class RemotePostAutosave: NSObject { - var title: String? - var excerpt: String? - var content: String? - var modifiedDate: Date? - var identifier: NSNumber? - var authorID: String? - var postID: NSNumber? - var previewURL: String? +@objc +@objcMembers +open class RemotePostAutosave: NSObject { + open var title: String? + open var excerpt: String? + open var content: String? + open var modifiedDate: Date? + open var identifier: NSNumber? + open var authorID: String? + open var postID: NSNumber? + open var previewURL: String? } From f8aaff88217f1d246916681406f3f60517901f46 Mon Sep 17 00:00:00 2001 From: Paul Von Schrottky Date: Sat, 2 Nov 2019 14:42:26 -0300 Subject: [PATCH 09/13] Add unit test to verify autosave mapping When the fetch posts REST endpoint is called, autosave properties are mapped to the RemotePost object. --- WordPressKit.xcodeproj/project.pbxproj | 10 +++- .../post-autosave-mapping-success.json | 38 +++++++++++++ .../PostServiceRemoteRESTAutosaveTests.swift | 54 +++++++++++++++++++ 3 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 WordPressKitTests/Mock Data/post-autosave-mapping-success.json create mode 100644 WordPressKitTests/PostServiceRemoteRESTAutosaveTests.swift diff --git a/WordPressKit.xcodeproj/project.pbxproj b/WordPressKit.xcodeproj/project.pbxproj index d608fa21..9d3db7af 100644 --- a/WordPressKit.xcodeproj/project.pbxproj +++ b/WordPressKit.xcodeproj/project.pbxproj @@ -17,6 +17,8 @@ 17CE77F420C701C8001DEA5A /* ReaderSiteSearchServiceRemoteTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17CE77F320C701C8001DEA5A /* ReaderSiteSearchServiceRemoteTests.swift */; }; 1A4F98672279A87D00D86E8E /* WPKit-Swift.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A4F98662279A87D00D86E8E /* WPKit-Swift.h */; settings = {ATTRIBUTES = (Private, ); }; }; 240315B0A1D6C2B981572B5B /* Pods_WordPressKitTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ED05C8FF3E61D93CE5BA527E /* Pods_WordPressKitTests.framework */; }; + 32A29A1F236BE4CC009488C2 /* post-autosave-mapping-success.json in Resources */ = {isa = PBXBuildFile; fileRef = 32A29A1E236BE4CC009488C2 /* post-autosave-mapping-success.json */; }; + 32AF21E3236DEB3C001C6502 /* PostServiceRemoteRESTAutosaveTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32AF21E2236DEB3C001C6502 /* PostServiceRemoteRESTAutosaveTests.swift */; }; 32E1DD23236AA09A008914B0 /* RemotePostAutosave.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32E1DD22236AA09A008914B0 /* RemotePostAutosave.swift */; }; 40247DFA2120D8E100AE1C3C /* AutomatedTransferService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40247DF92120D8E100AE1C3C /* AutomatedTransferService.swift */; }; 40247DFC2120E69600AE1C3C /* AutomatedTransferStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40247DFB2120E69600AE1C3C /* AutomatedTransferStatus.swift */; }; @@ -536,6 +538,8 @@ 17CE77F320C701C8001DEA5A /* ReaderSiteSearchServiceRemoteTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderSiteSearchServiceRemoteTests.swift; sourceTree = ""; }; 1A4F98662279A87D00D86E8E /* WPKit-Swift.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "WPKit-Swift.h"; sourceTree = ""; }; 264F5C834541BBF2018F4964 /* Pods-WordPressKitTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WordPressKitTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-WordPressKitTests/Pods-WordPressKitTests.debug.xcconfig"; sourceTree = ""; }; + 32A29A1E236BE4CC009488C2 /* post-autosave-mapping-success.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "post-autosave-mapping-success.json"; sourceTree = ""; }; + 32AF21E2236DEB3C001C6502 /* PostServiceRemoteRESTAutosaveTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostServiceRemoteRESTAutosaveTests.swift; sourceTree = ""; }; 32E1DD22236AA09A008914B0 /* RemotePostAutosave.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemotePostAutosave.swift; sourceTree = ""; }; 40247DF92120D8E100AE1C3C /* AutomatedTransferService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutomatedTransferService.swift; sourceTree = ""; }; 40247DFB2120E69600AE1C3C /* AutomatedTransferStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutomatedTransferStatus.swift; sourceTree = ""; }; @@ -1137,9 +1141,10 @@ 740B23D41F17F6D200067A2A /* Post */ = { isa = PBXGroup; children = ( + 32AF21E2236DEB3C001C6502 /* PostServiceRemoteRESTAutosaveTests.swift */, + 9AB6D649218727D60008F274 /* PostServiceRemoteRESTRevisionsTest.swift */, 740B23D01F17F6BB00067A2A /* PostServiceRemoteRESTTests.m */, 740B23D11F17F6BB00067A2A /* PostServiceRemoteXMLRPCTests.swift */, - 9AB6D649218727D60008F274 /* PostServiceRemoteRESTRevisionsTest.swift */, ); name = Post; sourceTree = ""; @@ -1723,6 +1728,7 @@ 40E4698C2017D2E30030DB5F /* plugin-directory-new.json */, 40E4698A2017C2840030DB5F /* plugin-directory-popular.json */, E1E89C651FD6B291006E7A33 /* plugin-directory-rename-xml-rpc.json */, + 32A29A1E236BE4CC009488C2 /* post-autosave-mapping-success.json */, 9AB6D648218722BB0008F274 /* post-revisions-success.json */, 9AB6D64D218731380008F274 /* post-revisions-mapping-success.json */, 9AB6D64C218730130008F274 /* post-revisions-failure.json */, @@ -2092,6 +2098,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 32A29A1F236BE4CC009488C2 /* post-autosave-mapping-success.json in Resources */, 93AC8EC61ED32FD000900F5A /* stats-v1.1-alltime.json in Resources */, 7403A2FC1EF06FEB00DED7DC /* me-settings-change-lastname-success.json in Resources */, 40F88F601F85723500AE3FAF /* auth-send-verification-email-already-verified-failure.json in Resources */, @@ -2582,6 +2589,7 @@ E13EE14C1F332C4400C15787 /* PluginServiceRemoteTests.swift in Sources */, 736C971021E80D48007A4200 /* SiteVerticalsPromptResponseDecodingTests.swift in Sources */, 74B335D81F06F1CA0053A184 /* MockWordPressComRestApi.swift in Sources */, + 32AF21E3236DEB3C001C6502 /* PostServiceRemoteRESTAutosaveTests.swift in Sources */, 74B5F0DE1EF82A9600B411E7 /* BlogServiceRemoteRESTTests.m in Sources */, 74E2294B1F1E73340085F7F2 /* SharingServiceRemoteTests.m in Sources */, 73B3DAD621FBB20D00B2CF18 /* WordPressComRestApiTests+Locale.swift in Sources */, diff --git a/WordPressKitTests/Mock Data/post-autosave-mapping-success.json b/WordPressKitTests/Mock Data/post-autosave-mapping-success.json new file mode 100644 index 00000000..648320ab --- /dev/null +++ b/WordPressKitTests/Mock Data/post-autosave-mapping-success.json @@ -0,0 +1,38 @@ +{ + "found": 3, + "posts": [ + { + "modified": "2019-10-28T02:05:52+00:00", + "title": "Hola, mundo!", + "status": "publish", + "meta": { + "links": { + "self": "https://public-api.wordpress.com/rest/v1.1/sites/168297153/posts/102", + "help": "https://public-api.wordpress.com/rest/v1.1/sites/168297153/posts/102/help", + "site": "https://public-api.wordpress.com/rest/v1.1/sites/168297153", + "replies": "https://public-api.wordpress.com/rest/v1.1/sites/168297153/posts/102/replies/", + "likes": "https://public-api.wordpress.com/rest/v1.1/sites/168297153/posts/102/likes/", + "autosave": "https://public-api.wordpress.com/rest/v1.1/sites/168297153/posts/102/autosave" + }, + "data": { + "autosave": { + "ID": 100, + "author_ID": "12345678", + "post_ID": 102, + "title": "Hello, world!", + "content": "\n

Uno.

\n", + "excerpt": "abc", + "preview_URL": "https://hello.wordpress.com/2019/10/28/hello-world/?preview=true&preview_nonce=07346f4e5d", + "modified": "2019-10-28T02:06:39+00:00" + } + } + } + } + ], + "meta": { + "links": { + "counts": "https://public-api.wordpress.com/rest/v1.1/sites/168297153/post-counts/post" + }, + "wpcom": true + } +} diff --git a/WordPressKitTests/PostServiceRemoteRESTAutosaveTests.swift b/WordPressKitTests/PostServiceRemoteRESTAutosaveTests.swift new file mode 100644 index 00000000..bcd8acda --- /dev/null +++ b/WordPressKitTests/PostServiceRemoteRESTAutosaveTests.swift @@ -0,0 +1,54 @@ +import Foundation +import XCTest + +@testable import WordPressKit + + +class PostServiceRemoteRESTAutosaveTests: RemoteTestCase, RESTTestable { + private let performPostsAutosaveSuccessFilename = "post-autosave-mapping-success.json" + private let siteId = 0 + private var remote: PostServiceRemoteREST! + private var postsEndpoint: String { + return "sites/\(siteId)/posts" + } + + override func setUp() { + super.setUp() + remote = PostServiceRemoteREST(wordPressComRestApi: getRestApi(), siteID: NSNumber(value: siteId)) + } + + override func tearDown() { + super.tearDown() + remote = nil + } + + + // MARK: Perform tests + + func testFetchPostsPerformsAutosaveMappingSuccessfully() { + let expect = expectation(description: "Fetch posts fetches autosaves successfully") + + stubRemoteResponse(postsEndpoint, filename: performPostsAutosaveSuccessFilename, contentType: .ApplicationJSON) + remote.getPostsOfType("", options: [:], success: { remotePosts in + + guard let remotePost = remotePosts?.first else { + XCTFail("Failed to retrieve mock post") + return + } + + XCTAssertEqual(remotePost.autosave.identifier?.intValue, 100) + XCTAssertEqual(remotePost.autosave.authorID, "12345678") + XCTAssertEqual(remotePost.autosave.postID, 102) + XCTAssertEqual(remotePost.autosave.title, "Hello, world!") + XCTAssertEqual(remotePost.autosave.content, "\n

Uno.

\n") + XCTAssertEqual(remotePost.autosave.excerpt, "abc") + XCTAssertEqual(remotePost.autosave.previewURL, "https://hello.wordpress.com/2019/10/28/hello-world/?preview=true&preview_nonce=07346f4e5d") + XCTAssertEqual(remotePost.autosave.modifiedDate, NSDate(wordPressComJSONString: "2019-10-28T02:06:39+00:00") as Date?) + expect.fulfill() + }, failure: { _ in + XCTFail("This callback shouldn't get called") + expect.fulfill() + }) + waitForExpectations(timeout: timeout, handler: nil) + } +} From a79aa2dc4b55bca7a67ca1b9deb925129ea16d64 Mon Sep 17 00:00:00 2001 From: Paul Von Schrottky Date: Tue, 5 Nov 2019 21:21:07 -0300 Subject: [PATCH 10/13] Updating pod version. --- WordPressKit.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPressKit.podspec b/WordPressKit.podspec index db1af666..70cedba3 100644 --- a/WordPressKit.podspec +++ b/WordPressKit.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "WordPressKit" - s.version = "4.5.3-beta.1" + s.version = "4.5.3-beta.2" s.summary = "WordPressKit offers a clean and simple WordPress.com and WordPress.org API." s.description = <<-DESC From 90d883a3ac46160da43588bcafc316707d48412c Mon Sep 17 00:00:00 2001 From: Paul Von Schrottky Date: Tue, 5 Nov 2019 21:21:51 -0300 Subject: [PATCH 11/13] Update documentation --- WordPressKit/RemotePost.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/WordPressKit/RemotePost.h b/WordPressKit/RemotePost.h index a03ad8c4..d4fa0ac2 100644 --- a/WordPressKit/RemotePost.h +++ b/WordPressKit/RemotePost.h @@ -35,7 +35,14 @@ extern NSString * const PostStatusDeleted; @property (nonatomic, strong) NSString *postThumbnailPath; @property (nonatomic, strong) NSString *type; @property (nonatomic, strong) NSString *format; + +/** +* A snapshot of the post at the last autosave. +* +* This is nullable. +*/ @property (nonatomic, strong) RemotePostAutosave *autosave; + @property (nonatomic, strong) NSNumber *commentCount; @property (nonatomic, strong) NSNumber *likeCount; From bfb8412e36db12da2e4b7f87a9662a90f49fc104 Mon Sep 17 00:00:00 2001 From: Paul Von Schrottky Date: Tue, 5 Nov 2019 21:22:08 -0300 Subject: [PATCH 12/13] Tighten access control on RemotePostAutosave `open` allowed subclassing of RemotePostAutosave and overriding of its properties, `public` disallows this. Further restiction to disallow setting the properties from outside the module using internal(set) doesn't work due to Obj-C interoperability issues. --- WordPressKit/RemotePostAutosave.swift | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/WordPressKit/RemotePostAutosave.swift b/WordPressKit/RemotePostAutosave.swift index 84f01c2e..fcc7c382 100644 --- a/WordPressKit/RemotePostAutosave.swift +++ b/WordPressKit/RemotePostAutosave.swift @@ -3,13 +3,13 @@ import Foundation /// Encapsulates the autosave attributes of a post. @objc @objcMembers -open class RemotePostAutosave: NSObject { - open var title: String? - open var excerpt: String? - open var content: String? - open var modifiedDate: Date? - open var identifier: NSNumber? - open var authorID: String? - open var postID: NSNumber? - open var previewURL: String? +public class RemotePostAutosave: NSObject { + public var title: String? + public var excerpt: String? + public var content: String? + public var modifiedDate: Date? + public var identifier: NSNumber? + public var authorID: String? + public var postID: NSNumber? + public var previewURL: String? } From 851cc8debeb4150c8fa35442434029f89d5e19de Mon Sep 17 00:00:00 2001 From: Paul Von Schrottky Date: Tue, 5 Nov 2019 23:19:25 -0300 Subject: [PATCH 13/13] Handle case when autosave is null If the fetch posts response JSON returns autosave as null, that's converted to NSNull, which is a truthy value. Updating to treat NSNull as no autosave. --- WordPressKit/PostServiceRemoteREST.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPressKit/PostServiceRemoteREST.m b/WordPressKit/PostServiceRemoteREST.m index 500351b2..2e8bf1e6 100644 --- a/WordPressKit/PostServiceRemoteREST.m +++ b/WordPressKit/PostServiceRemoteREST.m @@ -438,7 +438,7 @@ - (RemotePost *)remotePostFromJSONDictionary:(NSDictionary *)jsonPost { post.revisions = [jsonPost arrayForKey:@"revisions"]; NSDictionary *autosaveAttributes = jsonPost[@"meta"][@"data"][@"autosave"]; - if (autosaveAttributes) { + if ([autosaveAttributes wp_isValidObject]) { RemotePostAutosave *autosave = [[RemotePostAutosave alloc] init]; autosave.title = autosaveAttributes[@"title"]; autosave.content = autosaveAttributes[@"content"];