From 896707155bdf33dba71f4cb67e77a88631366565 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 12 Jul 2024 09:29:48 -0400 Subject: [PATCH 01/97] Remove WordPressShared dependency --- Podfile | 1 - Podfile.lock | 6 +----- Sources/CoreAPI/NonceRetrieval.swift | 1 - Sources/CoreAPI/WordPressComRestApi.swift | 1 - Sources/CoreAPI/WordPressOrgRestApi.swift | 1 - Sources/WordPressKit/Logging/WPKitLogging.h | 16 ++++++++++++---- Sources/WordPressKit/Logging/WPKitLogging.m | 8 ++++---- .../WordPressKit/Models/RemoteNotification.swift | 1 - Sources/WordPressKit/Models/RemotePerson.swift | 1 - Sources/WordPressKit/Models/RemoteReaderPost.m | 1 - .../Stats/Emails/StatsEmailsSummaryData.swift | 1 - .../Stats/StatsSubscribersSummaryData.swift | 1 - .../Services/AccountServiceRemoteREST.m | 1 - .../Services/AccountSettingsRemote.swift | 1 - .../Services/ActivityServiceRemote.swift | 1 - .../BlogJetpackSettingsServiceRemote.swift | 1 - .../Services/BlogServiceRemoteREST.m | 1 - .../Services/BlogServiceRemoteXMLRPC.m | 1 - .../Services/CommentServiceRemoteREST.m | 1 - .../Services/CommentServiceRemoteXMLRPC.m | 1 - .../Services/EditorServiceRemote.swift | 1 - .../Services/GravatarServiceRemote.swift | 1 - .../Services/JetpackBackupServiceRemote.swift | 1 - .../Services/JetpackScanServiceRemote.swift | 1 - .../Services/MediaServiceRemoteREST.m | 2 +- .../Services/MediaServiceRemoteXMLRPC.m | 1 - .../WordPressKit/Services/MenusServiceRemote.m | 2 +- .../NotificationSettingsServiceRemote.swift | 1 - .../Services/PeopleServiceRemote.swift | 1 - .../Services/Plans/PlanServiceRemote.swift | 1 - .../Plans/PlanServiceRemote_ApiVersion1_3.swift | 1 - .../Services/PostServiceRemoteREST.m | 2 +- .../Services/PostServiceRemoteXMLRPC.m | 1 - .../Services/QR Login/QRLoginServiceRemote.swift | 1 - .../Services/ReaderPostServiceRemote.m | 1 - .../Services/ReaderSiteSearchServiceRemote.swift | 1 - .../Services/ReaderSiteServiceRemote.m | 1 - .../Services/ReaderTopicServiceRemote.m | 1 - .../Services/SharingServiceRemote.swift | 1 - .../Services/SiteDesignServiceRemote.swift | 1 - .../Services/TaxonomyServiceRemoteREST.m | 1 - .../Services/TaxonomyServiceRemoteXMLRPC.m | 2 +- .../Services/TimeZoneServiceRemote.swift | 1 - .../Services/TransactionsServiceRemote.swift | 1 - .../Services/WordPressComServiceRemote.m | 1 - .../WordPressComRestApiTests+Locale.swift | 1 - .../CoreAPITests/WordPressComRestApiTests.swift | 1 - .../Tests/ReaderPostServiceRemoteTests.m | 1 - .../Tests/RemoteReaderPostTests.m | 1 - .../Tests/TransactionsServiceRemoteTests.swift | 1 - .../Tests/Utilities/LoggingTests.m | 2 +- .../Tests/Utilities/LoggingTests.swift | 2 +- WordPressKit.xcodeproj/project.pbxproj | 10 ++++++++-- .../xcshareddata/swiftpm/Package.resolved | 15 --------------- 54 files changed, 31 insertions(+), 79 deletions(-) delete mode 100644 WordPressKit.xcworkspace/xcshareddata/swiftpm/Package.resolved diff --git a/Podfile b/Podfile index 2b74b508..025097ca 100644 --- a/Podfile +++ b/Podfile @@ -16,7 +16,6 @@ def swiftlint_version end def wordpresskit_pods - pod 'WordPressShared', '~> 2.0.0-beta.2' pod 'NSObject-SafeExpectations', '~> 0.0.4' pod 'wpxmlrpc', '~> 0.10.0' pod 'UIDeviceIdentifier', '~> 2.0' diff --git a/Podfile.lock b/Podfile.lock index 83a6a853..01a0933c 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -19,7 +19,6 @@ PODS: - OHHTTPStubs/Default - SwiftLint (0.54.0) - UIDeviceIdentifier (2.3.0) - - WordPressShared (2.0.1) - wpxmlrpc (0.10.0) DEPENDENCIES: @@ -30,7 +29,6 @@ DEPENDENCIES: - OHHTTPStubs/Swift (~> 9.0) - SwiftLint (= 0.54.0) - UIDeviceIdentifier (~> 2.0) - - WordPressShared (~> 2.0.0-beta.2) - wpxmlrpc (~> 0.10.0) SPEC REPOS: @@ -41,7 +39,6 @@ SPEC REPOS: - OHHTTPStubs - SwiftLint - UIDeviceIdentifier - - WordPressShared - wpxmlrpc SPEC CHECKSUMS: @@ -51,9 +48,8 @@ SPEC CHECKSUMS: OHHTTPStubs: 90eac6d8f2c18317baeca36698523dc67c513831 SwiftLint: c1de071d9d08c8aba837545f6254315bc900e211 UIDeviceIdentifier: 442b65b4ff1832d4ca9c2a157815cb29ad981b17 - WordPressShared: f93f99269258b46dad04f4e4dbf540ce2e5c1e66 wpxmlrpc: 68db063041e85d186db21f674adf08d9c70627fd -PODFILE CHECKSUM: 64af6d71574c7a92d01a9446aa874e066917ebe5 +PODFILE CHECKSUM: d7336a949e31a4e569b4a06da5c8eac29f5eca45 COCOAPODS: 1.15.2 diff --git a/Sources/CoreAPI/NonceRetrieval.swift b/Sources/CoreAPI/NonceRetrieval.swift index b9e85a0c..14e13b15 100644 --- a/Sources/CoreAPI/NonceRetrieval.swift +++ b/Sources/CoreAPI/NonceRetrieval.swift @@ -1,5 +1,4 @@ import Foundation -import WordPressShared enum NonceRetrievalMethod { case newPostScrap diff --git a/Sources/CoreAPI/WordPressComRestApi.swift b/Sources/CoreAPI/WordPressComRestApi.swift index a8ebeb26..3b59624b 100644 --- a/Sources/CoreAPI/WordPressComRestApi.swift +++ b/Sources/CoreAPI/WordPressComRestApi.swift @@ -2,7 +2,6 @@ import APIInterface #endif import Foundation -import WordPressShared // MARK: - WordPressComRestApiError diff --git a/Sources/CoreAPI/WordPressOrgRestApi.swift b/Sources/CoreAPI/WordPressOrgRestApi.swift index 337ea298..30adcb2d 100644 --- a/Sources/CoreAPI/WordPressOrgRestApi.swift +++ b/Sources/CoreAPI/WordPressOrgRestApi.swift @@ -1,5 +1,4 @@ import Foundation -import WordPressShared public struct WordPressOrgRestApiError: LocalizedError, Decodable, HTTPURLResponseProviding { public enum CodingKeys: String, CodingKey { diff --git a/Sources/WordPressKit/Logging/WPKitLogging.h b/Sources/WordPressKit/Logging/WPKitLogging.h index 71b827aa..76ed2776 100644 --- a/Sources/WordPressKit/Logging/WPKitLogging.h +++ b/Sources/WordPressKit/Logging/WPKitLogging.h @@ -1,11 +1,19 @@ #import -@import WordPressShared; - NS_ASSUME_NONNULL_BEGIN -FOUNDATION_EXTERN id _Nullable WPKitGetLoggingDelegate(void); -FOUNDATION_EXTERN void WPKitSetLoggingDelegate(id _Nullable logger); +@protocol WordPressKitLoggingDelegate + +- (void)logError:(NSString *)str; +- (void)logWarning:(NSString *)str; +- (void)logInfo:(NSString *)str; +- (void)logDebug:(NSString *)str; +- (void)logVerbose:(NSString *)str; + +@end + +FOUNDATION_EXTERN id _Nullable WPKitGetLoggingDelegate(void); +FOUNDATION_EXTERN void WPKitSetLoggingDelegate(id _Nullable logger); FOUNDATION_EXTERN void WPKitLogError(NSString *str, ...) NS_FORMAT_FUNCTION(1, 2); FOUNDATION_EXTERN void WPKitLogWarning(NSString *str, ...) NS_FORMAT_FUNCTION(1, 2); diff --git a/Sources/WordPressKit/Logging/WPKitLogging.m b/Sources/WordPressKit/Logging/WPKitLogging.m index 59757186..d8a0607c 100644 --- a/Sources/WordPressKit/Logging/WPKitLogging.m +++ b/Sources/WordPressKit/Logging/WPKitLogging.m @@ -1,20 +1,20 @@ #import "WPKitLogging.h" -static id wordPressKitLogger = nil; +static id wordPressKitLogger = nil; -id _Nullable WPKitGetLoggingDelegate(void) +id _Nullable WPKitGetLoggingDelegate(void) { return wordPressKitLogger; } -void WPKitSetLoggingDelegate(id _Nullable logger) +void WPKitSetLoggingDelegate(id _Nullable logger) { wordPressKitLogger = logger; } #define WPKitLogv(logFunc) \ ({ \ - id logger = WPKitGetLoggingDelegate(); \ + id logger = WPKitGetLoggingDelegate(); \ if (logger == NULL) { \ NSLog(@"[WordPressKit] Warning: please call `WPKitSetLoggingDelegate` to set a error logger."); \ return; \ diff --git a/Sources/WordPressKit/Models/RemoteNotification.swift b/Sources/WordPressKit/Models/RemoteNotification.swift index 68923573..f97bfa2c 100644 --- a/Sources/WordPressKit/Models/RemoteNotification.swift +++ b/Sources/WordPressKit/Models/RemoteNotification.swift @@ -1,5 +1,4 @@ import Foundation -import WordPressShared // MARK: - RemoteNotification // diff --git a/Sources/WordPressKit/Models/RemotePerson.swift b/Sources/WordPressKit/Models/RemotePerson.swift index 3ce0c80e..3306be67 100644 --- a/Sources/WordPressKit/Models/RemotePerson.swift +++ b/Sources/WordPressKit/Models/RemotePerson.swift @@ -1,5 +1,4 @@ import Foundation -import WordPressShared // MARK: - Defines all of the peroperties a Person may have // diff --git a/Sources/WordPressKit/Models/RemoteReaderPost.m b/Sources/WordPressKit/Models/RemoteReaderPost.m index ee0032ed..190429f4 100644 --- a/Sources/WordPressKit/Models/RemoteReaderPost.m +++ b/Sources/WordPressKit/Models/RemoteReaderPost.m @@ -3,7 +3,6 @@ #import "WPKit-Swift.h" @import NSObject_SafeExpectations; -@import WordPressShared; // REST Post dictionary keys NSString * const PostRESTKeyAttachments = @"attachments"; diff --git a/Sources/WordPressKit/Models/Stats/Emails/StatsEmailsSummaryData.swift b/Sources/WordPressKit/Models/Stats/Emails/StatsEmailsSummaryData.swift index fe9fb03a..55267e0c 100644 --- a/Sources/WordPressKit/Models/Stats/Emails/StatsEmailsSummaryData.swift +++ b/Sources/WordPressKit/Models/Stats/Emails/StatsEmailsSummaryData.swift @@ -1,5 +1,4 @@ import Foundation -import WordPressShared public struct StatsEmailsSummaryData: Decodable, Equatable { public let posts: [Post] diff --git a/Sources/WordPressKit/Models/Stats/StatsSubscribersSummaryData.swift b/Sources/WordPressKit/Models/Stats/StatsSubscribersSummaryData.swift index 5ed9ee16..aece6030 100644 --- a/Sources/WordPressKit/Models/Stats/StatsSubscribersSummaryData.swift +++ b/Sources/WordPressKit/Models/Stats/StatsSubscribersSummaryData.swift @@ -1,5 +1,4 @@ import Foundation -import WordPressShared public struct StatsSubscribersSummaryData: Equatable { public let history: [SubscriberData] diff --git a/Sources/WordPressKit/Services/AccountServiceRemoteREST.m b/Sources/WordPressKit/Services/AccountServiceRemoteREST.m index 2d938c78..ebe7ad93 100644 --- a/Sources/WordPressKit/Services/AccountServiceRemoteREST.m +++ b/Sources/WordPressKit/Services/AccountServiceRemoteREST.m @@ -1,7 +1,6 @@ #import "AccountServiceRemoteREST.h" #import "WPKit-Swift.h" @import NSObject_SafeExpectations; -@import WordPressShared; static NSString * const UserDictionaryIDKey = @"ID"; static NSString * const UserDictionaryUsernameKey = @"username"; diff --git a/Sources/WordPressKit/Services/AccountSettingsRemote.swift b/Sources/WordPressKit/Services/AccountSettingsRemote.swift index e029ab5d..d00bed19 100644 --- a/Sources/WordPressKit/Services/AccountSettingsRemote.swift +++ b/Sources/WordPressKit/Services/AccountSettingsRemote.swift @@ -1,5 +1,4 @@ import Foundation -import WordPressShared public class AccountSettingsRemote: ServiceRemoteWordPressComREST { @objc public static let remotes = NSMapTable(keyOptions: NSPointerFunctions.Options(), valueOptions: NSPointerFunctions.Options.weakMemory) diff --git a/Sources/WordPressKit/Services/ActivityServiceRemote.swift b/Sources/WordPressKit/Services/ActivityServiceRemote.swift index d81ab327..317462bb 100644 --- a/Sources/WordPressKit/Services/ActivityServiceRemote.swift +++ b/Sources/WordPressKit/Services/ActivityServiceRemote.swift @@ -1,5 +1,4 @@ import Foundation -import WordPressShared open class ActivityServiceRemote: ServiceRemoteWordPressComREST { diff --git a/Sources/WordPressKit/Services/BlogJetpackSettingsServiceRemote.swift b/Sources/WordPressKit/Services/BlogJetpackSettingsServiceRemote.swift index 7ac03196..d12342a2 100644 --- a/Sources/WordPressKit/Services/BlogJetpackSettingsServiceRemote.swift +++ b/Sources/WordPressKit/Services/BlogJetpackSettingsServiceRemote.swift @@ -1,5 +1,4 @@ import Foundation -import WordPressShared public class BlogJetpackSettingsServiceRemote: ServiceRemoteWordPressComREST { diff --git a/Sources/WordPressKit/Services/BlogServiceRemoteREST.m b/Sources/WordPressKit/Services/BlogServiceRemoteREST.m index b8b3f140..7a07ec5e 100644 --- a/Sources/WordPressKit/Services/BlogServiceRemoteREST.m +++ b/Sources/WordPressKit/Services/BlogServiceRemoteREST.m @@ -4,7 +4,6 @@ #import "RemotePostType.h" #import "WPKit-Swift.h" @import NSObject_SafeExpectations; -@import WordPressShared; #pragma mark - Parsing Keys static NSString * const RemoteBlogNameKey = @"name"; diff --git a/Sources/WordPressKit/Services/BlogServiceRemoteXMLRPC.m b/Sources/WordPressKit/Services/BlogServiceRemoteXMLRPC.m index 9870919d..8dd769bb 100644 --- a/Sources/WordPressKit/Services/BlogServiceRemoteXMLRPC.m +++ b/Sources/WordPressKit/Services/BlogServiceRemoteXMLRPC.m @@ -3,7 +3,6 @@ #import "RemotePostType.h" #import "WPKit-Swift.h" @import NSObject_SafeExpectations; -@import WordPressShared; static NSString * const RemotePostTypeNameKey = @"name"; static NSString * const RemotePostTypeLabelKey = @"label"; diff --git a/Sources/WordPressKit/Services/CommentServiceRemoteREST.m b/Sources/WordPressKit/Services/CommentServiceRemoteREST.m index 0f13fddd..c3722d29 100644 --- a/Sources/WordPressKit/Services/CommentServiceRemoteREST.m +++ b/Sources/WordPressKit/Services/CommentServiceRemoteREST.m @@ -4,7 +4,6 @@ #import "RemoteUser.h" @import NSObject_SafeExpectations; -@import WordPressShared; @implementation CommentServiceRemoteREST diff --git a/Sources/WordPressKit/Services/CommentServiceRemoteXMLRPC.m b/Sources/WordPressKit/Services/CommentServiceRemoteXMLRPC.m index dfe05b5c..c3583737 100644 --- a/Sources/WordPressKit/Services/CommentServiceRemoteXMLRPC.m +++ b/Sources/WordPressKit/Services/CommentServiceRemoteXMLRPC.m @@ -3,7 +3,6 @@ #import "RemoteComment.h" @import wpxmlrpc; -@import WordPressShared; @import NSObject_SafeExpectations; @implementation CommentServiceRemoteXMLRPC diff --git a/Sources/WordPressKit/Services/EditorServiceRemote.swift b/Sources/WordPressKit/Services/EditorServiceRemote.swift index 1d5ba5f8..c6a7bf4d 100644 --- a/Sources/WordPressKit/Services/EditorServiceRemote.swift +++ b/Sources/WordPressKit/Services/EditorServiceRemote.swift @@ -1,5 +1,4 @@ import Foundation -import WordPressShared public class EditorServiceRemote: ServiceRemoteWordPressComREST { public func postDesignateMobileEditor(_ siteID: Int, editor: EditorSettings.Mobile, success: @escaping (EditorSettings) -> Void, failure: @escaping (Error) -> Void) { diff --git a/Sources/WordPressKit/Services/GravatarServiceRemote.swift b/Sources/WordPressKit/Services/GravatarServiceRemote.swift index 2f12cb9e..9604fc0c 100644 --- a/Sources/WordPressKit/Services/GravatarServiceRemote.swift +++ b/Sources/WordPressKit/Services/GravatarServiceRemote.swift @@ -1,5 +1,4 @@ import Foundation -import WordPressShared /// This ServiceRemote encapsulates all of the interaction with the Gravatar endpoint. /// diff --git a/Sources/WordPressKit/Services/JetpackBackupServiceRemote.swift b/Sources/WordPressKit/Services/JetpackBackupServiceRemote.swift index ce442915..3e613897 100644 --- a/Sources/WordPressKit/Services/JetpackBackupServiceRemote.swift +++ b/Sources/WordPressKit/Services/JetpackBackupServiceRemote.swift @@ -1,5 +1,4 @@ import Foundation -import WordPressShared open class JetpackBackupServiceRemote: ServiceRemoteWordPressComREST { diff --git a/Sources/WordPressKit/Services/JetpackScanServiceRemote.swift b/Sources/WordPressKit/Services/JetpackScanServiceRemote.swift index 0682d7b3..4ae9f725 100644 --- a/Sources/WordPressKit/Services/JetpackScanServiceRemote.swift +++ b/Sources/WordPressKit/Services/JetpackScanServiceRemote.swift @@ -1,5 +1,4 @@ import Foundation -import WordPressShared public class JetpackScanServiceRemote: ServiceRemoteWordPressComREST { // MARK: - Scanning diff --git a/Sources/WordPressKit/Services/MediaServiceRemoteREST.m b/Sources/WordPressKit/Services/MediaServiceRemoteREST.m index 5c50b085..eb883d2d 100644 --- a/Sources/WordPressKit/Services/MediaServiceRemoteREST.m +++ b/Sources/WordPressKit/Services/MediaServiceRemoteREST.m @@ -1,7 +1,7 @@ #import "MediaServiceRemoteREST.h" #import "RemoteMedia.h" #import "WPKit-Swift.h" -@import WordPressShared; + @import NSObject_SafeExpectations; const NSInteger WPRestErrorCodeMediaNew = 10; diff --git a/Sources/WordPressKit/Services/MediaServiceRemoteXMLRPC.m b/Sources/WordPressKit/Services/MediaServiceRemoteXMLRPC.m index 0d0059ea..2187c57d 100644 --- a/Sources/WordPressKit/Services/MediaServiceRemoteXMLRPC.m +++ b/Sources/WordPressKit/Services/MediaServiceRemoteXMLRPC.m @@ -2,7 +2,6 @@ #import "RemoteMedia.h" #import "WPKit-Swift.h" -@import WordPressShared; @import NSObject_SafeExpectations; @implementation MediaServiceRemoteXMLRPC diff --git a/Sources/WordPressKit/Services/MenusServiceRemote.m b/Sources/WordPressKit/Services/MenusServiceRemote.m index e7c0b145..52fe6384 100644 --- a/Sources/WordPressKit/Services/MenusServiceRemote.m +++ b/Sources/WordPressKit/Services/MenusServiceRemote.m @@ -1,6 +1,6 @@ #import "MenusServiceRemote.h" #import "WPKit-Swift.h" -@import WordPressShared; + @import NSObject_SafeExpectations; NS_ASSUME_NONNULL_BEGIN diff --git a/Sources/WordPressKit/Services/NotificationSettingsServiceRemote.swift b/Sources/WordPressKit/Services/NotificationSettingsServiceRemote.swift index 5e33682a..cd6de64b 100644 --- a/Sources/WordPressKit/Services/NotificationSettingsServiceRemote.swift +++ b/Sources/WordPressKit/Services/NotificationSettingsServiceRemote.swift @@ -1,6 +1,5 @@ import Foundation import UIDeviceIdentifier -import WordPressShared /// The purpose of this class is to encapsulate all of the interaction with the Notifications REST endpoints. /// Here we'll deal mostly with the Settings / Push Notifications API. diff --git a/Sources/WordPressKit/Services/PeopleServiceRemote.swift b/Sources/WordPressKit/Services/PeopleServiceRemote.swift index dd7d62af..e77ad169 100644 --- a/Sources/WordPressKit/Services/PeopleServiceRemote.swift +++ b/Sources/WordPressKit/Services/PeopleServiceRemote.swift @@ -1,5 +1,4 @@ import Foundation -import WordPressShared /// Encapsulates all of the People Management WordPress.com Methods /// diff --git a/Sources/WordPressKit/Services/Plans/PlanServiceRemote.swift b/Sources/WordPressKit/Services/Plans/PlanServiceRemote.swift index d654f394..cada673c 100644 --- a/Sources/WordPressKit/Services/Plans/PlanServiceRemote.swift +++ b/Sources/WordPressKit/Services/Plans/PlanServiceRemote.swift @@ -1,5 +1,4 @@ import Foundation -import WordPressShared public class PlanServiceRemote: ServiceRemoteWordPressComREST { public typealias AvailablePlans = (plans: [RemoteWpcomPlan], groups: [RemotePlanGroup], features: [RemotePlanFeature]) diff --git a/Sources/WordPressKit/Services/Plans/PlanServiceRemote_ApiVersion1_3.swift b/Sources/WordPressKit/Services/Plans/PlanServiceRemote_ApiVersion1_3.swift index b9fefa66..f64d3f9f 100644 --- a/Sources/WordPressKit/Services/Plans/PlanServiceRemote_ApiVersion1_3.swift +++ b/Sources/WordPressKit/Services/Plans/PlanServiceRemote_ApiVersion1_3.swift @@ -1,5 +1,4 @@ import Foundation -import WordPressShared @objc public class PlanServiceRemote_ApiVersion1_3: ServiceRemoteWordPressComREST { diff --git a/Sources/WordPressKit/Services/PostServiceRemoteREST.m b/Sources/WordPressKit/Services/PostServiceRemoteREST.m index e4455a61..6f1566c3 100644 --- a/Sources/WordPressKit/Services/PostServiceRemoteREST.m +++ b/Sources/WordPressKit/Services/PostServiceRemoteREST.m @@ -3,7 +3,7 @@ #import "RemotePostCategory.h" #import "RemoteUser.h" #import "WPKit-Swift.h" -@import WordPressShared; + @import NSObject_SafeExpectations; NSString * const PostRemoteStatusPublish = @"publish"; diff --git a/Sources/WordPressKit/Services/PostServiceRemoteXMLRPC.m b/Sources/WordPressKit/Services/PostServiceRemoteXMLRPC.m index e5454bc8..975a75b9 100644 --- a/Sources/WordPressKit/Services/PostServiceRemoteXMLRPC.m +++ b/Sources/WordPressKit/Services/PostServiceRemoteXMLRPC.m @@ -4,7 +4,6 @@ #import "NSMutableDictionary+Helpers.h" #import "WPKit-Swift.h" @import NSObject_SafeExpectations; -@import WordPressShared; const NSInteger HTTP404ErrorCode = 404; NSString * const WordPressAppErrorDomain = @"org.wordpress.iphone"; diff --git a/Sources/WordPressKit/Services/QR Login/QRLoginServiceRemote.swift b/Sources/WordPressKit/Services/QR Login/QRLoginServiceRemote.swift index db233527..a84aa6ba 100644 --- a/Sources/WordPressKit/Services/QR Login/QRLoginServiceRemote.swift +++ b/Sources/WordPressKit/Services/QR Login/QRLoginServiceRemote.swift @@ -1,5 +1,4 @@ import Foundation -import WordPressShared open class QRLoginServiceRemote: ServiceRemoteWordPressComREST { /// Validates the incoming QR Login token and retrieves the requesting browser, and location diff --git a/Sources/WordPressKit/Services/ReaderPostServiceRemote.m b/Sources/WordPressKit/Services/ReaderPostServiceRemote.m index 6cafe5f1..f02fe8c2 100644 --- a/Sources/WordPressKit/Services/ReaderPostServiceRemote.m +++ b/Sources/WordPressKit/Services/ReaderPostServiceRemote.m @@ -4,7 +4,6 @@ #import "ReaderTopicServiceRemote.h" #import "WPKit-Swift.h" @import NSObject_SafeExpectations; -@import WordPressShared; NSString * const PostRESTKeyPosts = @"posts"; diff --git a/Sources/WordPressKit/Services/ReaderSiteSearchServiceRemote.swift b/Sources/WordPressKit/Services/ReaderSiteSearchServiceRemote.swift index ae032969..03d4739c 100644 --- a/Sources/WordPressKit/Services/ReaderSiteSearchServiceRemote.swift +++ b/Sources/WordPressKit/Services/ReaderSiteSearchServiceRemote.swift @@ -1,5 +1,4 @@ import Foundation -import WordPressShared public class ReaderSiteSearchServiceRemote: ServiceRemoteWordPressComREST { diff --git a/Sources/WordPressKit/Services/ReaderSiteServiceRemote.m b/Sources/WordPressKit/Services/ReaderSiteServiceRemote.m index 44d278eb..1aa121ca 100644 --- a/Sources/WordPressKit/Services/ReaderSiteServiceRemote.m +++ b/Sources/WordPressKit/Services/ReaderSiteServiceRemote.m @@ -1,7 +1,6 @@ #import "ReaderSiteServiceRemote.h" #import "WPKit-Swift.h" @import NSObject_SafeExpectations; -@import WordPressShared; static NSString* const ReaderSiteServiceRemoteURLKey = @"url"; static NSString* const ReaderSiteServiceRemoteSourceKey = @"source"; diff --git a/Sources/WordPressKit/Services/ReaderTopicServiceRemote.m b/Sources/WordPressKit/Services/ReaderTopicServiceRemote.m index b78003d6..e1e61560 100644 --- a/Sources/WordPressKit/Services/ReaderTopicServiceRemote.m +++ b/Sources/WordPressKit/Services/ReaderTopicServiceRemote.m @@ -1,7 +1,6 @@ #import "ReaderTopicServiceRemote.h" #import "WPKit-Swift.h" @import NSObject_SafeExpectations; -@import WordPressShared; static NSString * const TopicMenuSectionDefaultKey = @"default"; static NSString * const TopicMenuSectionSubscribedKey = @"subscribed"; diff --git a/Sources/WordPressKit/Services/SharingServiceRemote.swift b/Sources/WordPressKit/Services/SharingServiceRemote.swift index 55433b6f..bafcd5e5 100644 --- a/Sources/WordPressKit/Services/SharingServiceRemote.swift +++ b/Sources/WordPressKit/Services/SharingServiceRemote.swift @@ -1,6 +1,5 @@ import Foundation import NSObject_SafeExpectations -import WordPressShared /// SharingServiceRemote is responsible for wrangling the REST API calls related to /// publiczice services, publicize connections, and keyring connections. diff --git a/Sources/WordPressKit/Services/SiteDesignServiceRemote.swift b/Sources/WordPressKit/Services/SiteDesignServiceRemote.swift index cab54481..fe208c93 100644 --- a/Sources/WordPressKit/Services/SiteDesignServiceRemote.swift +++ b/Sources/WordPressKit/Services/SiteDesignServiceRemote.swift @@ -1,5 +1,4 @@ import Foundation -import WordPressShared public struct SiteDesignRequest { public enum TemplateGroup: String { diff --git a/Sources/WordPressKit/Services/TaxonomyServiceRemoteREST.m b/Sources/WordPressKit/Services/TaxonomyServiceRemoteREST.m index c35291d9..0da3df5f 100644 --- a/Sources/WordPressKit/Services/TaxonomyServiceRemoteREST.m +++ b/Sources/WordPressKit/Services/TaxonomyServiceRemoteREST.m @@ -4,7 +4,6 @@ #import "RemotePostCategory.h" #import "WPKit-Swift.h" @import NSObject_SafeExpectations; -@import WordPressShared; NS_ASSUME_NONNULL_BEGIN diff --git a/Sources/WordPressKit/Services/TaxonomyServiceRemoteXMLRPC.m b/Sources/WordPressKit/Services/TaxonomyServiceRemoteXMLRPC.m index 9bf54e74..20bc4e26 100644 --- a/Sources/WordPressKit/Services/TaxonomyServiceRemoteXMLRPC.m +++ b/Sources/WordPressKit/Services/TaxonomyServiceRemoteXMLRPC.m @@ -2,7 +2,7 @@ #import "RemotePostTag.h" #import "RemoteTaxonomyPaging.h" #import "WPKit-Swift.h" -@import WordPressShared; + @import NSObject_SafeExpectations; NS_ASSUME_NONNULL_BEGIN diff --git a/Sources/WordPressKit/Services/TimeZoneServiceRemote.swift b/Sources/WordPressKit/Services/TimeZoneServiceRemote.swift index 42e4239f..500ac566 100644 --- a/Sources/WordPressKit/Services/TimeZoneServiceRemote.swift +++ b/Sources/WordPressKit/Services/TimeZoneServiceRemote.swift @@ -1,5 +1,4 @@ import Foundation -import WordPressShared public class TimeZoneServiceRemote: ServiceRemoteWordPressComREST { public enum ResponseError: Error { diff --git a/Sources/WordPressKit/Services/TransactionsServiceRemote.swift b/Sources/WordPressKit/Services/TransactionsServiceRemote.swift index 2ba8bf85..84eaaf29 100644 --- a/Sources/WordPressKit/Services/TransactionsServiceRemote.swift +++ b/Sources/WordPressKit/Services/TransactionsServiceRemote.swift @@ -1,5 +1,4 @@ import Foundation -import WordPressShared @objc public class TransactionsServiceRemote: ServiceRemoteWordPressComREST { diff --git a/Sources/WordPressKit/Services/WordPressComServiceRemote.m b/Sources/WordPressKit/Services/WordPressComServiceRemote.m index 28555c7e..196360c5 100644 --- a/Sources/WordPressKit/Services/WordPressComServiceRemote.m +++ b/Sources/WordPressKit/Services/WordPressComServiceRemote.m @@ -1,7 +1,6 @@ #import "WordPressComServiceRemote.h" #import "WPKit-Swift.h" @import NSObject_SafeExpectations; -@import WordPressShared; @implementation WordPressComServiceRemote diff --git a/Tests/CoreAPITests/WordPressComRestApiTests+Locale.swift b/Tests/CoreAPITests/WordPressComRestApiTests+Locale.swift index 0435003a..b5b4d56e 100644 --- a/Tests/CoreAPITests/WordPressComRestApiTests+Locale.swift +++ b/Tests/CoreAPITests/WordPressComRestApiTests+Locale.swift @@ -1,6 +1,5 @@ import XCTest import OHHTTPStubs -import WordPressShared #if SWIFT_PACKAGE @testable import CoreAPI import OHHTTPStubsSwift diff --git a/Tests/CoreAPITests/WordPressComRestApiTests.swift b/Tests/CoreAPITests/WordPressComRestApiTests.swift index a7f65b69..933f0a20 100644 --- a/Tests/CoreAPITests/WordPressComRestApiTests.swift +++ b/Tests/CoreAPITests/WordPressComRestApiTests.swift @@ -1,6 +1,5 @@ import XCTest import OHHTTPStubs -import WordPressShared #if SWIFT_PACKAGE import APIInterface @testable import CoreAPI diff --git a/Tests/WordPressKitTests/Tests/ReaderPostServiceRemoteTests.m b/Tests/WordPressKitTests/Tests/ReaderPostServiceRemoteTests.m index e48c7371..89ada39b 100644 --- a/Tests/WordPressKitTests/Tests/ReaderPostServiceRemoteTests.m +++ b/Tests/WordPressKitTests/Tests/ReaderPostServiceRemoteTests.m @@ -3,7 +3,6 @@ #import "ReaderPostServiceRemote.h" #import "RemoteReaderPost.h" #import "WPKit-Swift.h" -@import WordPressShared; @interface ReaderPostServiceRemoteTests : XCTestCase diff --git a/Tests/WordPressKitTests/Tests/RemoteReaderPostTests.m b/Tests/WordPressKitTests/Tests/RemoteReaderPostTests.m index 50a3c751..78804a77 100644 --- a/Tests/WordPressKitTests/Tests/RemoteReaderPostTests.m +++ b/Tests/WordPressKitTests/Tests/RemoteReaderPostTests.m @@ -4,7 +4,6 @@ #import "ReaderPostServiceRemote.h" #import "RemoteReaderPost.h" #import "WPKit-Swift.h" -@import WordPressShared; @interface RemoteReaderPost () diff --git a/Tests/WordPressKitTests/Tests/TransactionsServiceRemoteTests.swift b/Tests/WordPressKitTests/Tests/TransactionsServiceRemoteTests.swift index 1f98ea0c..8926780c 100644 --- a/Tests/WordPressKitTests/Tests/TransactionsServiceRemoteTests.swift +++ b/Tests/WordPressKitTests/Tests/TransactionsServiceRemoteTests.swift @@ -1,5 +1,4 @@ import XCTest -import WordPressShared @testable import WordPressKit class TransactionsServiceRemoteTests: RemoteTestCase, RESTTestable { diff --git a/Tests/WordPressKitTests/Tests/Utilities/LoggingTests.m b/Tests/WordPressKitTests/Tests/Utilities/LoggingTests.m index 60c4553b..62b06880 100644 --- a/Tests/WordPressKitTests/Tests/Utilities/LoggingTests.m +++ b/Tests/WordPressKitTests/Tests/Utilities/LoggingTests.m @@ -2,7 +2,7 @@ @import WordPressKit; -@interface CaptureLogs : NSObject +@interface CaptureLogs : NSObject @property (nonatomic, strong) NSMutableArray *infoLogs; @property (nonatomic, strong) NSMutableArray *errorLogs; diff --git a/Tests/WordPressKitTests/Tests/Utilities/LoggingTests.swift b/Tests/WordPressKitTests/Tests/Utilities/LoggingTests.swift index 0981ed16..8aee74b8 100644 --- a/Tests/WordPressKitTests/Tests/Utilities/LoggingTests.swift +++ b/Tests/WordPressKitTests/Tests/Utilities/LoggingTests.swift @@ -2,7 +2,7 @@ import XCTest @testable import WordPressKit -private class CaptureLogs: NSObject, WordPressLoggingDelegate { +private class CaptureLogs: NSObject, WordPressKitLoggingDelegate { private(set) var verboseLogs = [String]() private(set) var debugLogs = [String]() private(set) var infoLogs = [String]() diff --git a/WordPressKit.xcodeproj/project.pbxproj b/WordPressKit.xcodeproj/project.pbxproj index a83083cf..1e1b54ff 100644 --- a/WordPressKit.xcodeproj/project.pbxproj +++ b/WordPressKit.xcodeproj/project.pbxproj @@ -1570,6 +1570,13 @@ path = Assistant; sourceTree = ""; }; + 0C938A042C4166AC009BA7B2 /* WordPressShared */ = { + isa = PBXGroup; + children = ( + ); + path = WordPressShared; + sourceTree = ""; + }; 3297E1DC2564649D00287D21 /* Scan */ = { isa = PBXGroup; children = ( @@ -2122,6 +2129,7 @@ 3FE2E93F2BB11038002CA2E1 /* Models */, 3FE2E9402BB11075002CA2E1 /* Services */, 3FE2E9412BB110B3002CA2E1 /* Utility */, + 0C938A042C4166AC009BA7B2 /* WordPressShared */, 9368C77E1EC5EF1B0092CE8E /* WordPressKit.h */, 9368C77F1EC5EF1B0092CE8E /* Info.plist */, ); @@ -3274,7 +3282,6 @@ "${PODS_ROOT}/Target Support Files/Pods-WordPressKitTests/Pods-WordPressKitTests-frameworks.sh", "${BUILT_PRODUCTS_DIR}/NSObject-SafeExpectations/NSObject_SafeExpectations.framework", "${BUILT_PRODUCTS_DIR}/UIDeviceIdentifier/UIDeviceIdentifier.framework", - "${BUILT_PRODUCTS_DIR}/WordPressShared/WordPressShared.framework", "${BUILT_PRODUCTS_DIR}/wpxmlrpc/wpxmlrpc.framework", "${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework", "${BUILT_PRODUCTS_DIR}/OCMock/OCMock.framework", @@ -3284,7 +3291,6 @@ outputPaths = ( "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/NSObject_SafeExpectations.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/UIDeviceIdentifier.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/WordPressShared.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/wpxmlrpc.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Alamofire.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OCMock.framework", diff --git a/WordPressKit.xcworkspace/xcshareddata/swiftpm/Package.resolved b/WordPressKit.xcworkspace/xcshareddata/swiftpm/Package.resolved deleted file mode 100644 index 0cf274e7..00000000 --- a/WordPressKit.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ /dev/null @@ -1,15 +0,0 @@ -{ - "originHash" : "f28a54e288718485642adbe7b780a05abf05f95f0f435b3f87b6d3684b95d268", - "pins" : [ - { - "identity" : "test-collector-swift", - "kind" : "remoteSourceControl", - "location" : "https://github.com/buildkite/test-collector-swift", - "state" : { - "revision" : "6e46839e1a4507ee047acd0896e29b9b278d9e3a", - "version" : "0.4.0" - } - } - ], - "version" : 3 -} From f91298f119a7d6b1246a3bb643dde7e872f438e5 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 12 Jul 2024 09:52:43 -0400 Subject: [PATCH 02/97] Inline WordPressShared --- .../Models/Plugins/PluginDirectoryEntry.swift | 4 +- .../Models/RemoteBlogOptionsHelper.swift | 4 +- .../WordPressKit/Models/RemoteReaderPost.m | 22 +- .../Stats/Insights/StatsLastPostInsight.swift | 4 +- .../Services/AccountServiceRemoteREST.m | 4 +- .../Services/AccountSettingsRemote.swift | 2 +- .../Services/BlogServiceRemoteREST.m | 4 +- .../Services/BlogServiceRemoteXMLRPC.m | 4 +- .../Services/CommentServiceRemoteREST.m | 4 +- .../Services/CommentServiceRemoteXMLRPC.m | 2 +- .../Services/MediaServiceRemoteREST.m | 2 +- .../Services/MediaServiceRemoteXMLRPC.m | 2 +- .../Services/MenusServiceRemote.m | 6 +- .../NotificationSettingsServiceRemote.swift | 4 +- .../Services/PeopleServiceRemote.swift | 2 +- .../Services/PostServiceRemoteREST.m | 14 +- .../PostServiceRemoteXMLRPC+Extended.swift | 2 +- .../Services/PostServiceRemoteXMLRPC.m | 16 +- .../Services/ReaderPostServiceRemote.m | 6 +- .../Services/ReaderTopicServiceRemote.m | 6 +- .../Services/SharingServiceRemote.swift | 8 +- .../Services/TaxonomyServiceRemoteREST.m | 4 +- .../Services/TaxonomyServiceRemoteXMLRPC.m | 10 +- .../Services/WordPressComServiceRemote.m | 2 +- Sources/WordPressKit/WordPressKit.h | 8 + .../WordPressShared/Dictionary+Helpers.swift | 26 ++ .../WordPressShared/DisplayableImageHelper.h | 38 ++ .../WordPressShared/DisplayableImageHelper.m | 281 ++++++++++++ .../NSBundle+VersionNumberHelper.h | 7 + .../NSBundle+VersionNumberHelper.m | 11 + Sources/WordPressShared/NSDate+Helpers.swift | 257 +++++++++++ .../NSMutableData+Helpers.swift | 17 + Sources/WordPressShared/NSString+Helpers.h | 18 + Sources/WordPressShared/NSString+Helpers.m | 197 +++++++++ .../WordPressShared/NSString+Summary.swift | 79 ++++ .../WordPressShared/NSString+XMLExtensions.h | 10 + .../WordPressShared/NSString+XMLExtensions.m | 400 ++++++++++++++++++ Sources/WordPressShared/Secret.swift | 49 +++ Sources/WordPressShared/String+Helpers.swift | 167 ++++++++ Sources/WordPressShared/WPKitDateUtils.h | 8 + Sources/WordPressShared/WPKitDateUtils.m | 37 ++ Sources/WordPressShared/WPMapFilterReduce.h | 22 + Sources/WordPressShared/WPMapFilterReduce.m | 28 ++ .../WordPressComLanguageDatabase.swift | 367 ++++++++++++++++ WordPressKit.xcodeproj/project.pbxproj | 78 +++- 45 files changed, 2174 insertions(+), 69 deletions(-) create mode 100644 Sources/WordPressShared/Dictionary+Helpers.swift create mode 100644 Sources/WordPressShared/DisplayableImageHelper.h create mode 100644 Sources/WordPressShared/DisplayableImageHelper.m create mode 100644 Sources/WordPressShared/NSBundle+VersionNumberHelper.h create mode 100644 Sources/WordPressShared/NSBundle+VersionNumberHelper.m create mode 100644 Sources/WordPressShared/NSDate+Helpers.swift create mode 100644 Sources/WordPressShared/NSMutableData+Helpers.swift create mode 100644 Sources/WordPressShared/NSString+Helpers.h create mode 100644 Sources/WordPressShared/NSString+Helpers.m create mode 100644 Sources/WordPressShared/NSString+Summary.swift create mode 100644 Sources/WordPressShared/NSString+XMLExtensions.h create mode 100644 Sources/WordPressShared/NSString+XMLExtensions.m create mode 100644 Sources/WordPressShared/Secret.swift create mode 100644 Sources/WordPressShared/String+Helpers.swift create mode 100644 Sources/WordPressShared/WPKitDateUtils.h create mode 100644 Sources/WordPressShared/WPKitDateUtils.m create mode 100644 Sources/WordPressShared/WPMapFilterReduce.h create mode 100644 Sources/WordPressShared/WPMapFilterReduce.m create mode 100644 Sources/WordPressShared/WordPressComLanguageDatabase.swift diff --git a/Sources/WordPressKit/Models/Plugins/PluginDirectoryEntry.swift b/Sources/WordPressKit/Models/Plugins/PluginDirectoryEntry.swift index e377de16..3bd0dd59 100644 --- a/Sources/WordPressKit/Models/Plugins/PluginDirectoryEntry.swift +++ b/Sources/WordPressKit/Models/Plugins/PluginDirectoryEntry.swift @@ -77,7 +77,7 @@ extension PluginDirectoryEntry: Codable { public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) let decodedName = try container.decode(String.self, forKey: .name) - name = decodedName.stringByDecodingXMLCharacters() + name = decodedName.wpkit_stringByDecodingXMLCharacters() slug = try container.decode(String.self, forKey: .slug) version = try? container.decode(String.self, forKey: .version) lastUpdated = try? container.decode(Date.self, forKey: .lastUpdated) @@ -115,7 +115,7 @@ extension PluginDirectoryEntry: Codable { public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(name.stringByEncodingXMLCharacters(), forKey: .name) + try container.encode(name.wpkit_stringByEncodingXMLCharacters(), forKey: .name) try container.encode(slug, forKey: .slug) try container.encodeIfPresent(version, forKey: .version) try container.encodeIfPresent(lastUpdated, forKey: .lastUpdated) diff --git a/Sources/WordPressKit/Models/RemoteBlogOptionsHelper.swift b/Sources/WordPressKit/Models/RemoteBlogOptionsHelper.swift index 184960f3..aac09a7a 100644 --- a/Sources/WordPressKit/Models/RemoteBlogOptionsHelper.swift +++ b/Sources/WordPressKit/Models/RemoteBlogOptionsHelper.swift @@ -68,8 +68,8 @@ import Foundation public class func remoteBlogSettings(fromXMLRPCDictionaryOptions options: NSDictionary) -> RemoteBlogSettings { let remoteSettings = RemoteBlogSettings() - remoteSettings.name = options.string(forKeyPath: "blog_title.value")?.stringByDecodingXMLCharacters() - remoteSettings.tagline = options.string(forKeyPath: "blog_tagline.value")?.stringByDecodingXMLCharacters() + remoteSettings.name = options.string(forKeyPath: "blog_title.value")?.wpkit_stringByDecodingXMLCharacters() + remoteSettings.tagline = options.string(forKeyPath: "blog_tagline.value")?.wpkit_stringByDecodingXMLCharacters() if options["blog_public"] != nil { remoteSettings.privacy = options.number(forKeyPath: "blog_public.value") } diff --git a/Sources/WordPressKit/Models/RemoteReaderPost.m b/Sources/WordPressKit/Models/RemoteReaderPost.m index 190429f4..889a903c 100644 --- a/Sources/WordPressKit/Models/RemoteReaderPost.m +++ b/Sources/WordPressKit/Models/RemoteReaderPost.m @@ -94,7 +94,7 @@ - (instancetype)initWithDictionary:(NSDictionary *)dict; self.authorID = [authorDict numberForKey:PostRESTKeyID]; self.author = [self stringOrEmptyString:[authorDict stringForKey:PostRESTKeyNiceName]]; // typically the author's screen name self.authorAvatarURL = [self stringOrEmptyString:[authorDict stringForKey:PostRESTKeyAvatarURL]]; - self.authorDisplayName = [[self stringOrEmptyString:[authorDict stringForKey:PostRESTKeyName]] stringByDecodingXMLCharacters]; // Typically the author's given name + self.authorDisplayName = [[self stringOrEmptyString:[authorDict stringForKey:PostRESTKeyName]] wpkit_stringByDecodingXMLCharacters]; // Typically the author's given name self.authorEmail = [self authorEmailFromAuthorDictionary:authorDict]; self.authorURL = [self stringOrEmptyString:[authorDict stringForKey:PostRESTKeyURL]]; self.siteIconURL = [self stringOrEmptyString:[dict stringForKeyPath:@"meta.data.site.icon.img"]]; @@ -204,8 +204,8 @@ - (RemoteReaderCrossPostMeta *)crossPostMetaFromPostDictionary:(NSDictionary *)d } else if ([[obj stringForKey:CrossPostMetaKey] isEqualToString:CrossPostMetaXPostOrigin]) { NSString *value = [obj stringForKey:CrossPostMetaValue]; NSArray *IDS = [value componentsSeparatedByString:@":"]; - meta.siteID = [[IDS firstObject] numericValue]; - meta.postID = [[IDS lastObject] numericValue]; + meta.siteID = [[IDS firstObject] wpkit_numericValue]; + meta.postID = [[IDS lastObject] wpkit_numericValue]; crossPostMetaFound = YES; } @@ -270,8 +270,8 @@ - (NSDictionary *)primaryAndSecondaryTagsFromPostDictionary:(NSDictionary *)dict primaryTagSlug = editorialSlug; } - primaryTag = [primaryTag stringByDecodingXMLCharacters]; - secondaryTag = [secondaryTag stringByDecodingXMLCharacters]; + primaryTag = [primaryTag wpkit_stringByDecodingXMLCharacters]; + secondaryTag = [secondaryTag wpkit_stringByDecodingXMLCharacters]; return @{ TagKeyPrimary:primaryTag, @@ -472,7 +472,7 @@ - (NSDate *)sortDateFromPostDictionary:(NSDictionary *)dict sortDate = editorialDate; } - return [DateUtils dateFromISOString:sortDate]; + return [WPKitDateUtils dateFromISOString:sortDate]; } /** @@ -524,7 +524,7 @@ - (NSString *)featuredMediaImageFromPostDictionary:(NSDictionary *)dict { - (NSString *)suitableImageFromPostContent:(NSDictionary *)dict { NSString *content = [dict stringForKey:PostRESTKeyContent]; - NSString *imageToDisplay = [DisplayableImageHelper searchPostContentForImageToDisplay:content]; + NSString *imageToDisplay = [WPKitDisplayableImageHelper searchPostContentForImageToDisplay:content]; return [self stringOrEmptyString:imageToDisplay]; } @@ -650,7 +650,7 @@ - (BOOL)siteIsPrivateFromPostDictionary:(NSDictionary *)dict - (NSArray *)slugsFromDiscoverPostTaxonomies:(NSArray *)discoverPostTaxonomies { - return [discoverPostTaxonomies wp_map:^id(NSDictionary *dict) { + return [discoverPostTaxonomies wpkit_map:^id(NSDictionary *dict) { return [dict stringForKey:PostRESTKeySlug]; }]; } @@ -688,7 +688,7 @@ - (NSString *)formatSummary:(NSString *)summary */ - (NSString *)createSummaryFromContent:(NSString *)string { - return [string summarized]; + return [string wpkit_summarized]; } /** @@ -699,7 +699,7 @@ - (NSString *)createSummaryFromContent:(NSString *)string */ - (NSString *)makePlainText:(NSString *)string { - return [string summarized]; + return [string wpkit_summarized]; } /** @@ -710,7 +710,7 @@ - (NSString *)makePlainText:(NSString *)string */ - (NSString *)titleFromSummary:(NSString *)summary { - return [summary stringByEllipsizingWithMaxLength:ReaderPostTitleLength preserveWords:YES]; + return [summary wpkit_stringByEllipsizingWithMaxLength:ReaderPostTitleLength preserveWords:YES]; } diff --git a/Sources/WordPressKit/Models/Stats/Insights/StatsLastPostInsight.swift b/Sources/WordPressKit/Models/Stats/Insights/StatsLastPostInsight.swift index 6241a72d..9319c951 100644 --- a/Sources/WordPressKit/Models/Stats/Insights/StatsLastPostInsight.swift +++ b/Sources/WordPressKit/Models/Stats/Insights/StatsLastPostInsight.swift @@ -1,3 +1,5 @@ +import Foundation + public struct StatsLastPostInsight: Equatable, Decodable { public let title: String public let url: URL @@ -79,7 +81,7 @@ extension StatsLastPostInsight { public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) - title = try container.decode(String.self, forKey: .title).trimmingCharacters(in: .whitespaces).stringByDecodingXMLCharacters() + title = try container.decode(String.self, forKey: .title).trimmingCharacters(in: .whitespaces).wpkit_stringByDecodingXMLCharacters() url = try container.decode(URL.self, forKey: .url) let dateString = try container.decode(String.self, forKey: .publishedDate) guard let date = StatsLastPostInsight.dateFormatter.date(from: dateString) else { diff --git a/Sources/WordPressKit/Services/AccountServiceRemoteREST.m b/Sources/WordPressKit/Services/AccountServiceRemoteREST.m index ebe7ad93..a8290c2b 100644 --- a/Sources/WordPressKit/Services/AccountServiceRemoteREST.m +++ b/Sources/WordPressKit/Services/AccountServiceRemoteREST.m @@ -376,7 +376,7 @@ - (RemoteUser *)remoteUserFromDictionary:(NSDictionary *)dictionary remoteUser.displayName = [dictionary stringForKey:UserDictionaryDisplaynameKey]; remoteUser.primaryBlogID = [dictionary numberForKey:UserDictionaryPrimaryBlogKey]; remoteUser.avatarURL = [dictionary stringForKey:UserDictionaryAvatarURLKey]; - remoteUser.dateCreated = [NSDate dateWithISO8601String:[dictionary stringForKey:UserDictionaryDateKey]]; + remoteUser.dateCreated = [NSDate wpkit_dateWithISO8601String:[dictionary stringForKey:UserDictionaryDateKey]]; remoteUser.emailVerified = [[dictionary numberForKey:UserDictionaryEmailVerifiedKey] boolValue]; return remoteUser; @@ -385,7 +385,7 @@ - (RemoteUser *)remoteUserFromDictionary:(NSDictionary *)dictionary - (NSArray *)remoteBlogsFromJSONArray:(NSArray *)jsonBlogs { NSArray *blogs = jsonBlogs; - return [blogs wp_map:^id(NSDictionary *jsonBlog) { + return [blogs wpkit_map:^id(NSDictionary *jsonBlog) { return [[RemoteBlog alloc] initWithJSONDictionary:jsonBlog]; }]; return blogs; diff --git a/Sources/WordPressKit/Services/AccountSettingsRemote.swift b/Sources/WordPressKit/Services/AccountSettingsRemote.swift index d00bed19..7ed7751b 100644 --- a/Sources/WordPressKit/Services/AccountSettingsRemote.swift +++ b/Sources/WordPressKit/Services/AccountSettingsRemote.swift @@ -177,7 +177,7 @@ public class AccountSettingsRemote: ServiceRemoteWordPressComREST { throw ResponseError.decodingFailure } - let aboutMeText = aboutMe.decodingXMLCharacters() + let aboutMeText = aboutMe.wpkit_stringByDecodingXMLCharacters() return AccountSettings(firstName: firstName, lastName: lastName, diff --git a/Sources/WordPressKit/Services/BlogServiceRemoteREST.m b/Sources/WordPressKit/Services/BlogServiceRemoteREST.m index 7a07ec5e..69b22af9 100644 --- a/Sources/WordPressKit/Services/BlogServiceRemoteREST.m +++ b/Sources/WordPressKit/Services/BlogServiceRemoteREST.m @@ -142,7 +142,7 @@ - (void)syncPostTypesWithSuccess:(PostTypesHandler)success success:^(NSDictionary *responseObject, NSHTTPURLResponse *httpResponse) { NSAssert([responseObject isKindOfClass:[NSDictionary class]], @"Response should be a dictionary."); - NSArray *postTypes = [[responseObject arrayForKey:RemotePostTypesKey] wp_map:^id(NSDictionary *json) { + NSArray *postTypes = [[responseObject arrayForKey:RemotePostTypesKey] wpkit_map:^id(NSDictionary *json) { return [self remotePostTypeWithDictionary:json]; }]; if (!postTypes.count) { @@ -337,7 +337,7 @@ - (NSString *)pathForSettings - (NSArray *)usersFromJSONArray:(NSArray *)jsonUsers { - return [jsonUsers wp_map:^RemoteUser *(NSDictionary *jsonUser) { + return [jsonUsers wpkit_map:^RemoteUser *(NSDictionary *jsonUser) { return [self userFromJSONDictionary:jsonUser]; }]; } diff --git a/Sources/WordPressKit/Services/BlogServiceRemoteXMLRPC.m b/Sources/WordPressKit/Services/BlogServiceRemoteXMLRPC.m index 8dd769bb..3d7ff90a 100644 --- a/Sources/WordPressKit/Services/BlogServiceRemoteXMLRPC.m +++ b/Sources/WordPressKit/Services/BlogServiceRemoteXMLRPC.m @@ -46,7 +46,7 @@ - (void)getAllAuthorsWithRemoteUsers:(NSMutableArray *)remoteUsers [self.api callMethod:@"wp.getUsers" parameters:parameters success:^(id responseObject, NSHTTPURLResponse *response) { - NSArray *responseUsers = [[responseObject allObjects] wp_map:^id(NSDictionary *xmlrpcUser) { + NSArray *responseUsers = [[responseObject allObjects] wpkit_map:^id(NSDictionary *xmlrpcUser) { return [self remoteUserFromXMLRPCDictionary:xmlrpcUser]; }]; @@ -79,7 +79,7 @@ - (void)syncPostTypesWithSuccess:(PostTypesHandler)success failure:(void (^)(NSE success:^(id responseObject, NSHTTPURLResponse *response) { NSAssert([responseObject isKindOfClass:[NSDictionary class]], @"Response should be a dictionary."); - NSArray *postTypes = [[responseObject allObjects] wp_map:^id(NSDictionary *json) { + NSArray *postTypes = [[responseObject allObjects] wpkit_map:^id(NSDictionary *json) { return [self remotePostTypeFromXMLRPCDictionary:json]; }]; if (!postTypes.count) { diff --git a/Sources/WordPressKit/Services/CommentServiceRemoteREST.m b/Sources/WordPressKit/Services/CommentServiceRemoteREST.m index c3722d29..4b0f3761 100644 --- a/Sources/WordPressKit/Services/CommentServiceRemoteREST.m +++ b/Sources/WordPressKit/Services/CommentServiceRemoteREST.m @@ -463,7 +463,7 @@ - (void)getLikesForCommentID:(NSNumber *)commentID - (NSArray *)remoteCommentsFromJSONArray:(NSArray *)jsonComments { - return [jsonComments wp_map:^id(NSDictionary *jsonComment) { + return [jsonComments wpkit_map:^id(NSDictionary *jsonComment) { return [self remoteCommentFromJSONDictionary:jsonComment]; }]; } @@ -529,7 +529,7 @@ - (NSString *)remoteStatusWithStatus:(NSString *)status commentID:(NSNumber *)commentID siteID:(NSNumber *)siteID { - return [jsonUsers wp_map:^id(NSDictionary *jsonUser) { + return [jsonUsers wpkit_map:^id(NSDictionary *jsonUser) { return [[RemoteLikeUser alloc] initWithDictionary:jsonUser commentID:commentID siteID:siteID]; }]; } diff --git a/Sources/WordPressKit/Services/CommentServiceRemoteXMLRPC.m b/Sources/WordPressKit/Services/CommentServiceRemoteXMLRPC.m index c3583737..891c6c7c 100644 --- a/Sources/WordPressKit/Services/CommentServiceRemoteXMLRPC.m +++ b/Sources/WordPressKit/Services/CommentServiceRemoteXMLRPC.m @@ -203,7 +203,7 @@ - (void)trashComment:(RemoteComment *)comment - (NSArray *)remoteCommentsFromXMLRPCArray:(NSArray *)xmlrpcArray { - return [xmlrpcArray wp_map:^id(NSDictionary *xmlrpcComment) { + return [xmlrpcArray wpkit_map:^id(NSDictionary *xmlrpcComment) { return [self remoteCommentFromXMLRPCDictionary:xmlrpcComment]; }]; } diff --git a/Sources/WordPressKit/Services/MediaServiceRemoteREST.m b/Sources/WordPressKit/Services/MediaServiceRemoteREST.m index eb883d2d..90f38edf 100644 --- a/Sources/WordPressKit/Services/MediaServiceRemoteREST.m +++ b/Sources/WordPressKit/Services/MediaServiceRemoteREST.m @@ -386,7 +386,7 @@ -(void)getVideoPressToken:(NSString *)videoPressID + (NSArray *)remoteMediaFromJSONArray:(NSArray *)jsonMedia { - return [jsonMedia wp_map:^id(NSDictionary *json) { + return [jsonMedia wpkit_map:^id(NSDictionary *json) { return [self remoteMediaFromJSONDictionary:json]; }]; } diff --git a/Sources/WordPressKit/Services/MediaServiceRemoteXMLRPC.m b/Sources/WordPressKit/Services/MediaServiceRemoteXMLRPC.m index 2187c57d..ec04d042 100644 --- a/Sources/WordPressKit/Services/MediaServiceRemoteXMLRPC.m +++ b/Sources/WordPressKit/Services/MediaServiceRemoteXMLRPC.m @@ -263,7 +263,7 @@ -(void)getVideoPressToken:(NSString *)videoPressID - (NSArray *)remoteMediaFromXMLRPCArray:(NSArray *)xmlrpcArray { - return [xmlrpcArray wp_map:^id(NSDictionary *xmlrpcMedia) { + return [xmlrpcArray wpkit_map:^id(NSDictionary *xmlrpcMedia) { return [self remoteMediaFromXMLRPCDictionary:xmlrpcMedia]; }]; } diff --git a/Sources/WordPressKit/Services/MenusServiceRemote.m b/Sources/WordPressKit/Services/MenusServiceRemote.m index 52fe6384..bed046cd 100644 --- a/Sources/WordPressKit/Services/MenusServiceRemote.m +++ b/Sources/WordPressKit/Services/MenusServiceRemote.m @@ -194,7 +194,7 @@ - (void)getMenusForSiteID:(NSNumber *)siteID - (nullable NSArray *)remoteMenusFromJSONArray:(nullable NSArray *)jsonMenus { - return [jsonMenus wp_map:^id(NSDictionary *dictionary) { + return [jsonMenus wpkit_map:^id(NSDictionary *dictionary) { return [self menuFromJSONDictionary:dictionary]; }]; } @@ -202,7 +202,7 @@ - (nullable NSArray *)remoteMenusFromJSONArray:(nullable NSArray - (nullable NSArray *)menuItemsFromJSONDictionaries:(nullable NSArray *)dictionaries parent:(nullable RemoteMenuItem *)parent { NSParameterAssert([dictionaries isKindOfClass:[NSArray class]]); - return [dictionaries wp_map:^id(NSDictionary *dictionary) { + return [dictionaries wpkit_map:^id(NSDictionary *dictionary) { RemoteMenuItem *item = [self menuItemFromJSONDictionary:dictionary]; item.parentItem = parent; @@ -213,7 +213,7 @@ - (nullable NSArray *)menuItemsFromJSONDictionaries:(nullable NSArray *)jsonLocations { - return [jsonLocations wp_map:^id(NSDictionary *dictionary) { + return [jsonLocations wpkit_map:^id(NSDictionary *dictionary) { return [self menuLocationFromJSONDictionary:dictionary]; }]; } diff --git a/Sources/WordPressKit/Services/NotificationSettingsServiceRemote.swift b/Sources/WordPressKit/Services/NotificationSettingsServiceRemote.swift index cd6de64b..ca42d0bd 100644 --- a/Sources/WordPressKit/Services/NotificationSettingsServiceRemote.swift +++ b/Sources/WordPressKit/Services/NotificationSettingsServiceRemote.swift @@ -78,8 +78,8 @@ open class NotificationSettingsServiceRemote: ServiceRemoteWordPressComREST { "device_name": device.name, "device_model": UIDeviceHardware.platform(), "os_version": device.systemVersion, - "app_version": Bundle.main.bundleVersion(), - "device_uuid": device.wordPressIdentifier() + "app_version": Bundle.main.wpkit_bundleVersion(), + "device_uuid": device.identifierForVendor?.uuidString ] wordPressComRESTAPI.post(requestUrl, diff --git a/Sources/WordPressKit/Services/PeopleServiceRemote.swift b/Sources/WordPressKit/Services/PeopleServiceRemote.swift index e77ad169..e23b26ae 100644 --- a/Sources/WordPressKit/Services/PeopleServiceRemote.swift +++ b/Sources/WordPressKit/Services/PeopleServiceRemote.swift @@ -557,7 +557,7 @@ private extension PeopleServiceRemote { let firstName = user["first_name"] as? String let lastName = user["last_name"] as? String let avatarURL = (user["avatar_URL"] as? NSString) - .flatMap { URL(string: $0.byUrlEncoding())} + .flatMap { URL(string: $0.wpkit_stringByUrlEncoding())} let linkedUserID = user["linked_user_ID"] as? Int ?? ID let isSuperAdmin = user["is_super_admin"] as? Bool ?? false diff --git a/Sources/WordPressKit/Services/PostServiceRemoteREST.m b/Sources/WordPressKit/Services/PostServiceRemoteREST.m index 6f1566c3..f6ecf676 100644 --- a/Sources/WordPressKit/Services/PostServiceRemoteREST.m +++ b/Sources/WordPressKit/Services/PostServiceRemoteREST.m @@ -429,7 +429,7 @@ - (NSDictionary *)dictionaryWithRemoteOptions:(id )opt #pragma mark - Private methods - (NSArray *)remotePostsFromJSONArray:(NSArray *)jsonPosts { - return [jsonPosts wp_map:^id(NSDictionary *jsonPost) { + return [jsonPosts wpkit_map:^id(NSDictionary *jsonPost) { return [self remotePostFromJSONDictionary:jsonPost]; }]; } @@ -461,7 +461,7 @@ + (RemotePost *)remotePostFromJSONDictionary:(NSDictionary *)jsonPost { post.suggestedSlug = [jsonPost stringForKeyPath:@"other_URLs.suggested_slug"]; post.status = jsonPost[@"status"]; post.password = jsonPost[@"password"]; - if ([post.password isEmpty]) { + if ([post.password wpkit_isEmpty]) { post.password = nil; } post.parentID = [jsonPost numberForKeyPath:@"parent.ID"]; @@ -513,9 +513,9 @@ + (RemotePost *)remotePostFromJSONDictionary:(NSDictionary *)jsonPost { post.pathForDisplayImage = post.postThumbnailPath; } else { // parse contents for a suitable image - post.pathForDisplayImage = [DisplayableImageHelper searchPostContentForImageToDisplay:post.content]; + post.pathForDisplayImage = [WPKitDisplayableImageHelper searchPostContentForImageToDisplay:post.content]; if ([post.pathForDisplayImage length] == 0) { - post.pathForDisplayImage = [DisplayableImageHelper searchPostAttachmentsForImageToDisplay:[jsonPost dictionaryForKey:@"attachments"] existingInContent:post.content]; + post.pathForDisplayImage = [WPKitDisplayableImageHelper searchPostAttachmentsForImageToDisplay:[jsonPost dictionaryForKey:@"attachments"] existingInContent:post.content]; } } @@ -595,7 +595,7 @@ - (NSDictionary *)parametersWithRemotePost:(RemotePost *)post } - (NSArray *)metadataForPost:(RemotePost *)post { - return [post.metadata wp_map:^id(NSDictionary *meta) { + return [post.metadata wpkit_map:^id(NSDictionary *meta) { NSNumber *metaID = [meta objectForKey:@"id"]; NSString *metaValue = [meta objectForKey:@"value"]; NSString *metaKey = [meta objectForKey:@"key"]; @@ -616,7 +616,7 @@ - (NSArray *)metadataForPost:(RemotePost *)post { } + (NSArray *)remoteCategoriesFromJSONArray:(NSArray *)jsonCategories { - return [jsonCategories wp_map:^id(NSDictionary *jsonCategory) { + return [jsonCategories wpkit_map:^id(NSDictionary *jsonCategory) { return [self remoteCategoryFromJSONDictionary:jsonCategory]; }]; } @@ -646,7 +646,7 @@ + (NSArray *)tagNamesFromJSONDictionary:(NSDictionary *)jsonTags { postID:(NSNumber *)postID siteID:(NSNumber *)siteID { - return [jsonUsers wp_map:^id(NSDictionary *jsonUser) { + return [jsonUsers wpkit_map:^id(NSDictionary *jsonUser) { return [[RemoteLikeUser alloc] initWithDictionary:jsonUser postID:postID siteID:siteID]; }]; } diff --git a/Sources/WordPressKit/Services/PostServiceRemoteXMLRPC+Extended.swift b/Sources/WordPressKit/Services/PostServiceRemoteXMLRPC+Extended.swift index 904941fd..50265480 100644 --- a/Sources/WordPressKit/Services/PostServiceRemoteXMLRPC+Extended.swift +++ b/Sources/WordPressKit/Services/PostServiceRemoteXMLRPC+Extended.swift @@ -20,7 +20,7 @@ extension PostServiceRemoteXMLRPC: PostServiceRemoteExtended { let dictionary = try makeParameters(from: RemotePostCreateParametersXMLRPCEncoder(parameters: parameters)) let parameters = xmlrpcArguments(withExtra: dictionary) as [AnyObject] let response = try await api.call(method: "wp.newPost", parameters: parameters).get() - guard let postID = (response.body as? NSObject)?.numericValue() else { + guard let postID = (response.body as? NSObject)?.wpkit_numericValue() else { throw URLError(.unknown) // Should never happen } return try await post(withID: postID.intValue) diff --git a/Sources/WordPressKit/Services/PostServiceRemoteXMLRPC.m b/Sources/WordPressKit/Services/PostServiceRemoteXMLRPC.m index 975a75b9..d6432e20 100644 --- a/Sources/WordPressKit/Services/PostServiceRemoteXMLRPC.m +++ b/Sources/WordPressKit/Services/PostServiceRemoteXMLRPC.m @@ -89,8 +89,8 @@ - (void)createPost:(RemotePost *)post [self.api callMethod:@"metaWeblog.newPost" parameters:parameters success:^(id responseObject, NSHTTPURLResponse *httpResponse) { - if ([responseObject respondsToSelector:@selector(numericValue)]) { - post.postID = [responseObject numericValue]; + if ([responseObject respondsToSelector:@selector(wpkit_numericValue)]) { + post.postID = [responseObject wpkit_numericValue]; if (!post.date) { // Set the temporary date until we get it from the server so it sorts properly on the list @@ -287,7 +287,7 @@ - (NSDictionary *)dictionaryWithRemoteOptions:(id )opt #pragma mark - Private methods - (NSArray *)remotePostsFromXMLRPCArray:(NSArray *)xmlrpcArray { - return [xmlrpcArray wp_map:^id(NSDictionary *xmlrpcPost) { + return [xmlrpcArray wpkit_map:^id(NSDictionary *xmlrpcPost) { return [self remotePostFromXMLRPCDictionary:xmlrpcPost]; }]; } @@ -312,7 +312,7 @@ + (RemotePost *)remotePostFromXMLRPCDictionary:(NSDictionary *)xmlrpcDictionary post.authorID = [xmlrpcDictionary numberForKey:@"post_author"]; post.status = [self statusForPostStatus:xmlrpcDictionary[@"post_status"] andDate:post.date]; post.password = xmlrpcDictionary[@"post_password"]; - if ([post.password isEmpty]) { + if ([post.password wpkit_isEmpty]) { post.password = nil; } post.parentID = [xmlrpcDictionary numberForKey:@"post_parent"]; @@ -336,7 +336,7 @@ + (RemotePost *)remotePostFromXMLRPCDictionary:(NSDictionary *)xmlrpcDictionary post.pathForDisplayImage = post.postThumbnailPath; } else { // parse content for a suitable image. - post.pathForDisplayImage = [DisplayableImageHelper searchPostContentForImageToDisplay:post.content]; + post.pathForDisplayImage = [WPKitDisplayableImageHelper searchPostContentForImageToDisplay:post.content]; } return post; @@ -358,9 +358,9 @@ + (NSArray *)tagsFromXMLRPCTermsArray:(NSArray *)terms { } + (NSArray *)remoteCategoriesFromXMLRPCTermsArray:(NSArray *)terms { - return [[terms wp_filter:^BOOL(NSDictionary *category) { + return [[terms wpkit_filter:^BOOL(NSDictionary *category) { return [[category stringForKey:@"taxonomy"] isEqualToString:@"category"]; - }] wp_map:^id(NSDictionary *category) { + }] wpkit_map:^id(NSDictionary *category) { return [self remoteCategoryFromXMLRPCDictionary:category]; }]; } @@ -410,7 +410,7 @@ - (NSDictionary *)parametersWithRemotePost:(RemotePost *)post postParams[@"date_created_gmt"] = [NSDate date]; } if (post.categories) { - NSArray *categoryNames = [post.categories wp_map:^id(RemotePostCategory *category) { + NSArray *categoryNames = [post.categories wpkit_map:^id(RemotePostCategory *category) { return category.name; }]; diff --git a/Sources/WordPressKit/Services/ReaderPostServiceRemote.m b/Sources/WordPressKit/Services/ReaderPostServiceRemote.m index f02fe8c2..46da6729 100644 --- a/Sources/WordPressKit/Services/ReaderPostServiceRemote.m +++ b/Sources/WordPressKit/Services/ReaderPostServiceRemote.m @@ -29,7 +29,7 @@ - (void)fetchPostsFromEndpoint:(NSURL *)endpoint NSNumber *numberToFetch = @(count); NSMutableDictionary *params = [@{ ParamKeyNumber:numberToFetch, - ParamKeyBefore: [DateUtils isoStringFromDate:date], + ParamKeyBefore: [WPKitDateUtils isoStringFromDate:date], ParamKeyOrder: ParamKeyDescending, ParamKeyMeta: ParamKeyMetaValue } mutableCopy]; @@ -178,7 +178,7 @@ - (NSString *)endpointUrlForSearchPhrase:(NSString *)phrase { NSAssert([phrase length] > 0, @"A search phrase is required."); - NSString *endpoint = [NSString stringWithFormat:@"read/search?q=%@", [phrase stringByUrlEncoding]]; + NSString *endpoint = [NSString stringWithFormat:@"read/search?q=%@", [phrase wpkit_stringByUrlEncoding]]; NSString *absolutePath = [self pathForEndpoint:endpoint withVersion:WordPressComRESTAPIVersion_1_2]; NSURL *url = [NSURL URLWithString:absolutePath relativeToURL:self.wordPressComRESTAPI.baseURL]; return [url absoluteString]; @@ -218,7 +218,7 @@ - (void)fetchPostsFromEndpoint:(NSURL *)endpoint __block CGFloat offset = [[params numberForKey:ParamKeyOffset] floatValue]; NSString *algorithm = [responseObject stringForKey:ParamsKeyAlgorithm]; NSArray *jsonPosts = [responseObject arrayForKey:PostRESTKeyPosts]; - NSArray *posts = [jsonPosts wp_map:^id(NSDictionary *jsonPost) { + NSArray *posts = [jsonPosts wpkit_map:^id(NSDictionary *jsonPost) { if (rankByOffset) { RemoteReaderPost *post = [self formatPostDictionary:jsonPost offset:offset]; offset++; diff --git a/Sources/WordPressKit/Services/ReaderTopicServiceRemote.m b/Sources/WordPressKit/Services/ReaderTopicServiceRemote.m index e1e61560..9078367e 100644 --- a/Sources/WordPressKit/Services/ReaderTopicServiceRemote.m +++ b/Sources/WordPressKit/Services/ReaderTopicServiceRemote.m @@ -267,7 +267,7 @@ - (NSString *)slugForTopicName:(NSString *)topicName regexNonAlphaNumNonDash = [NSRegularExpression regularExpressionWithPattern:@"[^\\p{L}\\p{Nd}\\-]+" options:NSRegularExpressionCaseInsensitive error:&error]; }); - topicName = [[topicName lowercaseString] trim]; + topicName = [[topicName lowercaseString] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; // remove html entities topicName = [regexHtmlEntities stringByReplacingMatchesInString:topicName @@ -299,9 +299,9 @@ - (NSString *)slugForTopicName:(NSString *)topicName - (NSArray *)normalizeMenuTopicsList:(NSArray *)rawTopics subscribed:(BOOL)subscribed recommended:(BOOL)recommended { - return [[rawTopics wp_filter:^BOOL(id obj) { + return [[rawTopics wpkit_filter:^BOOL(id obj) { return [obj isKindOfClass:[NSDictionary class]]; - }] wp_map:^id(NSDictionary *topic) { + }] wpkit_map:^id(NSDictionary *topic) { return [self normalizeMenuTopicDictionary:topic subscribed:subscribed recommended:recommended]; }]; } diff --git a/Sources/WordPressKit/Services/SharingServiceRemote.swift b/Sources/WordPressKit/Services/SharingServiceRemote.swift index bafcd5e5..a6bd0e6e 100644 --- a/Sources/WordPressKit/Services/SharingServiceRemote.swift +++ b/Sources/WordPressKit/Services/SharingServiceRemote.swift @@ -113,8 +113,8 @@ open class SharingServiceRemote: ServiceRemoteWordPressComREST { let dict = dict as AnyObject let externalUsers = dict.array(forKey: ConnectionDictionaryKeys.additionalExternalUsers) ?? [] conn.additionalExternalUsers = self.externalUsersForKeyringConnection(externalUsers as NSArray) - conn.dateExpires = DateUtils.date(fromISOString: dict.string(forKey: ConnectionDictionaryKeys.expires)) - conn.dateIssued = DateUtils.date(fromISOString: dict.string(forKey: ConnectionDictionaryKeys.issued)) + conn.dateExpires = WPKitDateUtils.date(fromISOString: dict.string(forKey: ConnectionDictionaryKeys.expires)) + conn.dateIssued = WPKitDateUtils.date(fromISOString: dict.string(forKey: ConnectionDictionaryKeys.issued)) conn.externalDisplay = dict.string(forKey: ConnectionDictionaryKeys.externalDisplay) ?? conn.externalDisplay conn.externalID = dict.string(forKey: ConnectionDictionaryKeys.externalID) ?? conn.externalID conn.externalName = dict.string(forKey: ConnectionDictionaryKeys.externalName) ?? conn.externalName @@ -369,11 +369,11 @@ open class SharingServiceRemote: ServiceRemoteWordPressComREST { conn.service = dict.string(forKey: ConnectionDictionaryKeys.service) ?? conn.service if let expirationDateAsString = dict.string(forKey: ConnectionDictionaryKeys.expires) { - conn.dateExpires = DateUtils.date(fromISOString: expirationDateAsString) + conn.dateExpires = WPKitDateUtils.date(fromISOString: expirationDateAsString) } if let issueDateAsString = dict.string(forKey: ConnectionDictionaryKeys.issued) { - conn.dateIssued = DateUtils.date(fromISOString: issueDateAsString) + conn.dateIssued = WPKitDateUtils.date(fromISOString: issueDateAsString) } if let sharedDictNumber = dict.number(forKey: ConnectionDictionaryKeys.shared) { diff --git a/Sources/WordPressKit/Services/TaxonomyServiceRemoteREST.m b/Sources/WordPressKit/Services/TaxonomyServiceRemoteREST.m index 0da3df5f..4dbc4ee1 100644 --- a/Sources/WordPressKit/Services/TaxonomyServiceRemoteREST.m +++ b/Sources/WordPressKit/Services/TaxonomyServiceRemoteREST.m @@ -282,7 +282,7 @@ - (void)updateTaxonomyWithType:(NSString *)typeIdentifier - (NSArray *)remoteCategoriesWithJSONArray:(NSArray *)jsonArray { - return [jsonArray wp_map:^id(NSDictionary *jsonCategory) { + return [jsonArray wpkit_map:^id(NSDictionary *jsonCategory) { return [self remoteCategoryWithJSONDictionary:jsonCategory]; }]; } @@ -298,7 +298,7 @@ - (RemotePostCategory *)remoteCategoryWithJSONDictionary:(NSDictionary *)jsonCat - (NSArray *)remoteTagsWithJSONArray:(NSArray *)jsonArray { - return [jsonArray wp_map:^id(NSDictionary *jsonTag) { + return [jsonArray wpkit_map:^id(NSDictionary *jsonTag) { return [self remoteTagWithJSONDictionary:jsonTag]; }]; } diff --git a/Sources/WordPressKit/Services/TaxonomyServiceRemoteXMLRPC.m b/Sources/WordPressKit/Services/TaxonomyServiceRemoteXMLRPC.m index 20bc4e26..6e11502d 100644 --- a/Sources/WordPressKit/Services/TaxonomyServiceRemoteXMLRPC.m +++ b/Sources/WordPressKit/Services/TaxonomyServiceRemoteXMLRPC.m @@ -41,7 +41,7 @@ - (void)createCategory:(RemotePostCategory *)category success:^(NSString *responseString) { RemotePostCategory *newCategory = [RemotePostCategory new]; NSString *categoryID = responseString; - newCategory.categoryID = [categoryID numericValue]; + newCategory.categoryID = [categoryID wpkit_numericValue]; if (success) { success(newCategory); } @@ -96,7 +96,7 @@ - (void)createTag:(RemotePostTag *)tag success:^(NSString *responseString) { RemotePostTag *newTag = [RemotePostTag new]; NSString *tagID = responseString; - newTag.tagID = [tagID numericValue]; + newTag.tagID = [tagID wpkit_numericValue]; newTag.name = tag.name; newTag.tagDescription = tag.tagDescription; newTag.slug = tag.slug; @@ -187,7 +187,7 @@ - (void)createTaxonomyWithType:(NSString *)typeIdentifier [self.api callMethod:@"wp.newTerm" parameters:xmlrpcParameters success:^(id responseObject, NSHTTPURLResponse *httpResponse) { - if (![responseObject respondsToSelector:@selector(numericValue)]) { + if (![responseObject respondsToSelector:@selector(wpkit_numericValue)]) { NSString *message = [NSString stringWithFormat:@"Invalid response creating taxonomy of type: %@", typeIdentifier]; [self handleResponseErrorWithMessage:message method:@"wp.newTerm" failure:failure]; return; @@ -286,7 +286,7 @@ - (void)editTaxonomyWithType:(NSString *)typeIdentifier - (NSArray *)remoteCategoriesFromXMLRPCArray:(NSArray *)xmlrpcArray { - return [xmlrpcArray wp_map:^id(NSDictionary *xmlrpcCategory) { + return [xmlrpcArray wpkit_map:^id(NSDictionary *xmlrpcCategory) { return [self remoteCategoryFromXMLRPCDictionary:xmlrpcCategory]; }]; } @@ -302,7 +302,7 @@ - (RemotePostCategory *)remoteCategoryFromXMLRPCDictionary:(NSDictionary *)xmlrp - (NSArray *)remoteTagsFromXMLRPCArray:(NSArray *)xmlrpcArray { - return [xmlrpcArray wp_map:^id(NSDictionary *xmlrpcTag) { + return [xmlrpcArray wpkit_map:^id(NSDictionary *xmlrpcTag) { return [self remoteTagFromXMLRPCDictionary:xmlrpcTag]; }]; } diff --git a/Sources/WordPressKit/Services/WordPressComServiceRemote.m b/Sources/WordPressKit/Services/WordPressComServiceRemote.m index 196360c5..0db615a5 100644 --- a/Sources/WordPressKit/Services/WordPressComServiceRemote.m +++ b/Sources/WordPressKit/Services/WordPressComServiceRemote.m @@ -244,7 +244,7 @@ - (NSError *)errorWithLocalizedMessage:(NSError *)error { - (NSString *)errorMessageForError:(NSError *)error { NSString *errorCode = [error.userInfo stringForKey:WordPressComRestApi.ErrorKeyErrorCode]; - NSString *errorMessage = [[error.userInfo stringForKey:NSLocalizedDescriptionKey] stringByStrippingHTML]; + NSString *errorMessage = [[error.userInfo stringForKey:NSLocalizedDescriptionKey] wpkit_stringByStrippingHTML]; if ([errorCode isEqualToString:@"username_only_lowercase_letters_and_numbers"]) { return NSLocalizedString(@"Sorry, usernames can only contain lowercase letters (a-z) and numbers.", nil); diff --git a/Sources/WordPressKit/WordPressKit.h b/Sources/WordPressKit/WordPressKit.h index 482fdb30..67570367 100644 --- a/Sources/WordPressKit/WordPressKit.h +++ b/Sources/WordPressKit/WordPressKit.h @@ -55,3 +55,11 @@ FOUNDATION_EXPORT const unsigned char WordPressKitVersionString[]; #import #import + +/// Inline WordPressShared +#import +#import +#import +#import +#import +#import diff --git a/Sources/WordPressShared/Dictionary+Helpers.swift b/Sources/WordPressShared/Dictionary+Helpers.swift new file mode 100644 index 00000000..f981af95 --- /dev/null +++ b/Sources/WordPressShared/Dictionary+Helpers.swift @@ -0,0 +1,26 @@ +import Foundation + + +// MARK: - Dictionary Helper Methods +// +extension Dictionary { + /// This method attempts to convert a given value into a String, if it's not already the + /// case. Initial implementation supports only NSNumber. This is meant for bulletproof parsing, + /// in which a String value might be serialized, backend side, as a Number. + /// + /// - Parameter key: The key to retrieve. + /// + /// - Returns: Value as a String (when possible!) + /// + func valueAsString(forKey key: Key) -> String? { + let value = self[key] + switch value { + case let string as String: + return string + case let number as NSNumber: + return number.description + default: + return nil + } + } +} diff --git a/Sources/WordPressShared/DisplayableImageHelper.h b/Sources/WordPressShared/DisplayableImageHelper.h new file mode 100644 index 00000000..06e2a7e1 --- /dev/null +++ b/Sources/WordPressShared/DisplayableImageHelper.h @@ -0,0 +1,38 @@ +#import + +/** + Helper for searching a post's content or attachments for an image suitable for + using as the displayed image in the post list. + */ +@interface WPKitDisplayableImageHelper : NSObject + +/** + Get the url path of the image to display for a post. + + @param attachmentsDict A dictionary representing a posts attachments from the REST API. + @param content The post content. The attachment url must exist in the content. + @return The url path for the featured image or nil + */ ++ (NSString *)searchPostAttachmentsForImageToDisplay:(NSDictionary *)attachmentsDict existingInContent:(NSString *)content; + +/** + Search the passed string for an image that is a good candidate to feature. + + @details Loops over all img tags in the passed html content, extracts the URL from the + src attribute and checks for an acceptable width. The image URL with the best + width is returned. + @param content The content string to search. + @return The URL path for the image or an empty string. + */ ++ (NSString *)searchPostContentForImageToDisplay:(NSString *)content; + +/** + Find attachments ids in post content + + @param content The content string to search + + @return A set with all the attachment id that where found in galleries + */ ++ (NSSet *)searchPostContentForAttachmentIdsInGalleries:(NSString *)content; + +@end diff --git a/Sources/WordPressShared/DisplayableImageHelper.m b/Sources/WordPressShared/DisplayableImageHelper.m new file mode 100644 index 00000000..d8d360c1 --- /dev/null +++ b/Sources/WordPressShared/DisplayableImageHelper.m @@ -0,0 +1,281 @@ +#import "DisplayableImageHelper.h" +#import "NSString+Helpers.h" + +static const NSInteger FeaturedImageMinimumWidth = 150; + +static NSString * const AttachmentsDictionaryKeyWidth = @"width"; +static NSString * const AttachmentsDictionaryKeyURL = @"URL"; +static NSString * const AttachmentsDictionaryKeyMimeType = @"mime_type"; + +@implementation WPKitDisplayableImageHelper + ++ (NSInteger)widthOfAttachment:(NSDictionary *)attachment { + NSInteger result = 0; + id obj = [attachment objectForKey:AttachmentsDictionaryKeyWidth]; + if ([obj isKindOfClass:NSNumber.class]) { + NSNumber *number = (NSNumber *)obj; + result = [number integerValue]; + } else if ([obj isKindOfClass:NSString.class]) { + NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init]; + numberFormatter.locale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"]; + NSNumber *number= [numberFormatter numberFromString:(NSString *)obj]; + result = [number integerValue]; + } + return result; +} + ++ (NSString *)searchPostAttachmentsForImageToDisplay:(NSDictionary *)attachmentsDict existingInContent:(NSString *)content +{ + NSArray *attachments = [attachmentsDict allValues]; + if ([attachments count] == 0) { + return nil; + } + + NSString *imageToDisplay; + + attachments = [self filteredAttachmentsArray:attachments]; + + for (NSDictionary *attachment in attachments) { + NSInteger width = [self widthOfAttachment:attachment]; + if (width < FeaturedImageMinimumWidth) { + // The remaining images are too small so just stop now. + break; + } + id obj = attachment[AttachmentsDictionaryKeyURL]; + if ([obj isKindOfClass:NSString.class]) { + NSString *maybeImage = (NSString *)obj; + if ([content containsString:maybeImage]) { + imageToDisplay = maybeImage; + break; + } + } + } + + return imageToDisplay; +} + ++ (NSArray *)filteredAttachmentsArray:(NSArray *)attachments +{ + NSString *key = AttachmentsDictionaryKeyMimeType; + NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%K BEGINSWITH %@", key, @"image"]; + attachments = [attachments filteredArrayUsingPredicate:predicate]; + attachments = [self sortAttachmentsArray:attachments]; + return attachments; +} + ++ (NSArray *)sortAttachmentsArray:(NSArray *)attachments +{ + return [attachments sortedArrayUsingComparator:^NSComparisonResult(NSDictionary *attachmentA, NSDictionary *attachmentB) { + NSInteger widthA = [self widthOfAttachment:attachmentA]; + NSInteger widthB = [self widthOfAttachment:attachmentB]; + + if (widthA < widthB) { + return NSOrderedDescending; + } else if (widthA > widthB) { + return NSOrderedAscending; + } else { + return NSOrderedSame; + } + }]; +} + ++ (NSString *)searchPostContentForImageToDisplay:(NSString *)content +{ + NSString *imageSrc = @""; + // If there is no image tag in the content, just bail. + if (!content || [content rangeOfString:@""; + regex = [NSRegularExpression regularExpressionWithPattern:imgPattern options:NSRegularExpressionCaseInsensitive error:&error]; + }); + + // Find all the image tags in the content passed. + NSArray *matches = [regex matchesInString:content options:0 range:NSMakeRange(0, [content length])]; + + for (NSTextCheckingResult *match in matches) { + NSString *tag = [content substringWithRange:match.range]; + NSString *src = [self extractSrcFromImgTag:tag]; + + // Ignore WordPress emoji images + if ([src rangeOfString:@"/images/core/emoji/"].location != NSNotFound || + [src rangeOfString:@"/wp-includes/images/smilies/"].location != NSNotFound || + [src rangeOfString:@"/wp-content/mu-plugins/wpcom-smileys/"].location != NSNotFound) { + continue; + } + + // Ignore .svg images since we can't display them in a UIImageView + if ([src rangeOfString:@".svg"].location != NSNotFound) { + continue; + } + + // Check the tag for a good width + NSInteger width = MAX([self widthFromElementAttribute:tag], [self widthFromQueryString:src]); + if (width > FeaturedImageMinimumWidth) { + imageSrc = src; + break; + } + } + if (imageSrc.length == 0) { + imageSrc = [self searchContentBySizeClassForImageToFeature:content]; + } + + return imageSrc; +} + ++ (NSSet *)searchPostContentForAttachmentIdsInGalleries:(NSString *)content +{ + NSMutableSet *resultSet = [NSMutableSet set]; + // If there is no gallery shortcode in the content, just bail. + if (!content || [content rangeOfString:@"[gallery "].location == NSNotFound) { + return resultSet; + } + + // Get all the things + static NSRegularExpression *regexGallery; + static dispatch_once_t onceTokenRegexGallery; + dispatch_once(&onceTokenRegexGallery, ^{ + NSError *error; + NSString *galleryPattern = @"\\[gallery[^]]+ids=\"([0-9,]*)\"[^]]*\\]"; + regexGallery = [NSRegularExpression regularExpressionWithPattern:galleryPattern options:NSRegularExpressionCaseInsensitive error:&error]; + }); + + // Find all the gallery shortcodes in the content passed. + NSArray *matches = [regexGallery matchesInString:content options:0 range:NSMakeRange(0, [content length])]; + + for (NSTextCheckingResult *match in matches) { + if (match.numberOfRanges < 2) { + continue; + } + NSString *tag = [content substringWithRange:[match rangeAtIndex:1]]; + NSSet *tagIds = [self idsFromGallery:tag]; + [resultSet unionSet:tagIds]; + } + return resultSet; +} + +/** + Extract the path to an image from an image tag. + + @param tag An image tag. + @return The value of the src param. + */ ++ (NSString *)extractSrcFromImgTag:(NSString *)tag +{ + static NSRegularExpression *regex; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSError *error; + NSString *srcPattern = @"src\\s*=\\s*(?:'|\")(.*?)(?:'|\")"; + regex = [NSRegularExpression regularExpressionWithPattern:srcPattern options:NSRegularExpressionCaseInsensitive error:&error]; + }); + + NSRange srcRng = [regex rangeOfFirstMatchInString:tag options:0 range:NSMakeRange(0, [tag length])]; + NSString *src = [tag substringWithRange:srcRng]; + NSCharacterSet *charSet = [NSCharacterSet characterSetWithCharactersInString:@"\"'="]; + NSRange quoteRng = [src rangeOfCharacterFromSet:charSet]; + src = [src substringFromIndex:quoteRng.location]; + src = [src stringByTrimmingCharactersInSet:charSet]; + return src; +} + +/** + Search the passed string for an image that is a good candidate to feature. + @param content The content string to search. + @return The url path for the image or an empty string. + */ ++ (NSString *)searchContentBySizeClassForImageToFeature:(NSString *)content +{ + NSString *str = @""; + // If there is no image tag in the content, just bail. + if (!content || [content rangeOfString:@" + +@interface NSBundle (WPKitVersionNumberHelper) + +- (NSString *)wpkit_bundleVersion; + +@end diff --git a/Sources/WordPressShared/NSBundle+VersionNumberHelper.m b/Sources/WordPressShared/NSBundle+VersionNumberHelper.m new file mode 100644 index 00000000..736c2bdf --- /dev/null +++ b/Sources/WordPressShared/NSBundle+VersionNumberHelper.m @@ -0,0 +1,11 @@ +#import "NSBundle+VersionNumberHelper.h" + +@implementation NSBundle (WPKitVersionNumberHelper) + +- (NSString *)wpkit_bundleVersion +{ + NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary]; + return infoDictionary[(NSString *)kCFBundleVersionKey] ?: [NSString new]; +} + +@end diff --git a/Sources/WordPressShared/NSDate+Helpers.swift b/Sources/WordPressShared/NSDate+Helpers.swift new file mode 100644 index 00000000..9dabadc6 --- /dev/null +++ b/Sources/WordPressShared/NSDate+Helpers.swift @@ -0,0 +1,257 @@ +import Foundation + +extension Date { + /// Private Date Formatters + /// + fileprivate struct DateFormatters { + static let iso8601: DateFormatter = { + let formatter = DateFormatter() + formatter.locale = Locale(identifier: "en_US_POSIX") + formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ" + formatter.timeZone = TimeZone(secondsFromGMT: 0) + return formatter + }() + + static let iso8601WithMilliseconds: DateFormatter = { + let formatter = DateFormatter() + formatter.locale = Locale(identifier: "en_US_POSIX") + formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSXXXXX" + formatter.timeZone = TimeZone(secondsFromGMT: 0) + return formatter + }() + + static let rfc1123: DateFormatter = { + let formatter = DateFormatter() + formatter.locale = Locale(identifier: "en_US_POSIX") + formatter.dateFormat = "EEE, dd MMM yyyy HH:mm:ss z" + formatter.timeZone = TimeZone(secondsFromGMT: 0) + return formatter + }() + + static let mediumDate: DateFormatter = { + let formatter = DateFormatter() + formatter.dateStyle = .medium + formatter.timeStyle = .none + return formatter + }() + + static let mediumDateTime: DateFormatter = { + let formatter = DateFormatter() + formatter.doesRelativeDateFormatting = true + formatter.dateStyle = .medium + formatter.timeStyle = .short + return formatter + }() + + static let mediumUTCDateTime: DateFormatter = { + let formatter = DateFormatter() + formatter.dateStyle = .medium + formatter.timeStyle = .short + formatter.timeZone = TimeZone(secondsFromGMT: 0) + return formatter + }() + + static let longUTCDate: DateFormatter = { + let formatter = DateFormatter() + formatter.dateStyle = .long + formatter.timeStyle = .none + formatter.timeZone = TimeZone(secondsFromGMT: 0) + return formatter + }() + + static let shortDateTime: DateFormatter = { + let formatter = DateFormatter() + formatter.doesRelativeDateFormatting = true + formatter.dateStyle = .short + formatter.timeStyle = .short + return formatter + }() + } + + /// Returns a NSDate Instance, given it's ISO8601 String Representation + /// + static func dateWithISO8601String(_ string: String) -> Date? { + return DateFormatters.iso8601.date(from: string) + } + + /// Returns a NSDate Instance, given it's ISO8601 String Representation with milliseconds + /// + static func dateWithISO8601WithMillisecondsString(_ string: String) -> Date? { + return DateFormatters.iso8601WithMilliseconds.date(from: string) + } + + /// Returns a NSDate instance with only its Year / Month / Weekday / Day set. Removes the time! + /// + func normalizedDate() -> Date { + + var calendar = Calendar.current + calendar.timeZone = TimeZone.autoupdatingCurrent + + let flags: NSCalendar.Unit = [.day, .weekOfYear, .month, .year] + + let components = (calendar as NSCalendar).components(flags, from: self) + + var normalized = DateComponents() + normalized.year = components.year + normalized.month = components.month + normalized.weekday = components.weekday + normalized.day = components.day + + return calendar.date(from: normalized) ?? self + } + + /// Formats the current NSDate instance using the RFC1123 Standard + /// + func toStringAsRFC1123() -> String { + return DateFormatters.rfc1123.string(from: self) + } + + @available(*, deprecated, renamed: "toMediumString", message: "Removed to help drop the deprecated `FormatterKit` dependency – @jkmassel, Mar 2021") + func mediumString(timeZone: TimeZone? = nil) -> String { + toMediumString(inTimeZone: timeZone) + } + + /// Formats the current date as relative date if it's within a week of + /// today, or with DateFormatter.Style.medium otherwise. + /// - Parameter timeZone: An optional time zone used to adjust the date formatters. **NOTE**: This has no affect on relative time stamps. + /// + /// - Example: 22 hours from now + /// - Example: 5 minutes ago + /// - Example: 8 hours ago + /// - Example: 2 days ago + /// - Example: Jan 22, 2017 + /// + func toMediumString(inTimeZone timeZone: TimeZone? = nil) -> String { + let relativeFormatter = RelativeDateTimeFormatter() + relativeFormatter.dateTimeStyle = .named + + let absoluteFormatter = DateFormatters.mediumDate + + if let timeZone = timeZone { + absoluteFormatter.timeZone = timeZone + } + + let components = Calendar.current.dateComponents([.day], from: self, to: Date()) + if let days = components.day, abs(days) < 7 { + return relativeFormatter.localizedString(fromTimeInterval: timeIntervalSinceNow) + } else { + return absoluteFormatter.string(from: self) + } + } + + /// Formats the current date as a medium relative date/time. + /// That is, it uses the `DateFormatter` `dateStyle` `.medium` and `timeStyle` `.short`. + /// + /// - Parameter timeZone: An optional time zone used to adjust the date formatters. + func mediumStringWithTime(timeZone: TimeZone? = nil) -> String { + let formatter = DateFormatters.mediumDateTime + if let timeZone = timeZone { + formatter.timeZone = timeZone + } + return formatter.string(from: self) + } + + /// Formats the current date as (non relative) long date (no time) in UTC. + /// + /// - Example: January 6th, 2018 + /// + func longUTCStringWithoutTime() -> String { + return DateFormatters.longUTCDate.string(from: self) + } + + /// Formats the current date as (non relattive) medium date/time in UTC. + /// + /// - Example: Jan 28, 2017, 1:51 PM + /// + func mediumStringWithUTCTime() -> String { + return DateFormatters.mediumUTCDateTime.string(from: self) + } + + /// Formats the current date as a short relative date/time. + /// + /// - Example: Tomorrow, 6:45 AM + /// - Example: Today, 8:09 AM + /// - Example: Yesterday, 11:36 PM + /// - Example: 1/28/17, 1:51 PM + /// - Example: 1/22/17, 2:18 AM + /// + func shortStringWithTime() -> String { + return DateFormatters.shortDateTime.string(from: self) + } + + @available(*, deprecated, message: "Not used, as far as I can tell – @jkmassel, Jan 2021") + fileprivate func toStringForPageSections() -> String { + let interval = timeIntervalSinceNow + + if interval > 0 && interval < 86400 { + return NSLocalizedString("later today", comment: "Later today") + } else { + let formatter = RelativeDateTimeFormatter() + formatter.unitsStyle = .short + formatter.dateTimeStyle = .named + + return formatter.localizedString(fromTimeInterval: interval) + } + } + + /// Returns the date components object. + /// + func dateAndTimeComponents() -> DateComponents { + return Calendar.current.dateComponents([.year, .month, .day, .hour, .minute, .second], + from: self) + } +} + +extension NSDate { + @objc public static func wpkit_dateWithISO8601String(_ string: String) -> NSDate? { + return Date.DateFormatters.iso8601.date(from: string) as NSDate? + } + + /// Formats the current date as relative date if it's within a week of + /// today, or with NSDateFormatterMediumStyle otherwise. + /// + /// - Example: 22 hours from now + /// - Example: 5 minutes ago + /// - Example: 8 hours ago + /// - Example: 2 days ago + /// - Example: Jan 22, 2017 + /// + @objc func mediumString() -> String { + return (self as Date).toMediumString() + } + + /// Formats the current date as a medium relative date/time. + /// + /// - Example: Tomorrow, 6:45 AM + /// - Example: Today, 8:09 AM + /// - Example: Yesterday, 11:36 PM + /// - Example: Jan 28, 2017, 1:51 PM + /// - Example: Jan 22, 2017, 2:18 AM + /// + @objc func mediumStringWithTime() -> String { + return (self as Date).mediumStringWithTime() + } + + /// Formats the current date as a short relative date/time. + /// + /// - Example: Tomorrow, 6:45 AM + /// - Example: Today, 8:09 AM + /// - Example: Yesterday, 11:36 PM + /// - Example: 1/28/17, 1:51 PM + /// - Example: 1/22/17, 2:18 AM + /// + @objc func shortStringWithTime() -> String { + return (self as Date).shortStringWithTime() + } + + @available(*, deprecated, message: "Scheduled for removal with FormatterKit – if it's still used, we'll rewrite it with modern APIs") + @objc func toStringForPageSections() -> String { + return (self as Date).toStringForPageSections() + } + + /// Returns the date components object. + /// + @objc func dateAndTimeComponents() -> NSDateComponents { + return (self as Date).dateAndTimeComponents() as NSDateComponents + } +} diff --git a/Sources/WordPressShared/NSMutableData+Helpers.swift b/Sources/WordPressShared/NSMutableData+Helpers.swift new file mode 100644 index 00000000..0983d7dd --- /dev/null +++ b/Sources/WordPressShared/NSMutableData+Helpers.swift @@ -0,0 +1,17 @@ +import Foundation + + +/// Encapsulates all of the NSMutableData Helper Methods. +/// +extension NSMutableData { + + /// Encodes a raw String into UTF8, and appends it to the current instance. + /// + /// - Parameter string: The raw String to be UTF8-Encoded, and appended + /// + @objc func appendString(_ string: String) { + if let data = string.data(using: String.Encoding.utf8) { + append(data) + } + } +} diff --git a/Sources/WordPressShared/NSString+Helpers.h b/Sources/WordPressShared/NSString+Helpers.h new file mode 100644 index 00000000..a6f28ced --- /dev/null +++ b/Sources/WordPressShared/NSString+Helpers.h @@ -0,0 +1,18 @@ +#import + +@interface NSString (WPKitHelpers) + +- (NSString *)wpkit_stringByUrlEncoding; +- (NSString *)wpkit_stringByStrippingHTML; +- (NSString *)wpkit_stringByEllipsizingWithMaxLength:(NSInteger)lengthlimit preserveWords:(BOOL)preserveWords; +- (bool)wpkit_isEmpty; + +@end + +@interface NSString (WPKitNumericValueHack) +- (NSNumber *)wpkit_numericValue; +@end + +@interface NSObject (WPKitNumericValueHack) +- (NSNumber *)wpkit_numericValue; +@end diff --git a/Sources/WordPressShared/NSString+Helpers.m b/Sources/WordPressShared/NSString+Helpers.m new file mode 100644 index 00000000..43930bd7 --- /dev/null +++ b/Sources/WordPressShared/NSString+Helpers.m @@ -0,0 +1,197 @@ +#import "NSString+Helpers.h" +#import +#import "NSString+XMLExtensions.h" + +static NSString *const Ellipsis = @"\u2026"; + +@implementation NSString (WPKitHelpers) + +#pragma mark Helpers + +/** + Parses an WordPress core emoji IMG tag and returns the corresponding emoji character. + */ ++ (NSString *)emojiFromCoreEmojiImageTag:(NSString *)tag +{ + if ([tag rangeOfString:@" 0) { + NSTextCheckingResult *match = [matches firstObject]; + if (match.numberOfRanges == 2) { + NSRange range = [match rangeAtIndex:1]; + return [tag substringWithRange:range]; + } + } + + matches = [filenameRegex matchesInString:tag options:0 range:sourceRange]; + if ([matches count] > 0) { + NSTextCheckingResult *match = [matches firstObject]; + if (match.numberOfRanges == 2) { + NSRange range = [match rangeAtIndex:1]; + NSString *filename = [tag substringWithRange:range]; + return [self emojiCharacterFromCoreEmojiFilename:filename]; + } + } + + return nil; +} + +/** + Processes the filename of an core emoji image from `s.w.org/images/core/emoji` + and returns the unicode character for the emoji. + Filenames can be formatted as a single hex value, or for emoji comprised of + Unicode pairs, as two hex values separated by a dash. + */ ++ (NSString *)emojiCharacterFromCoreEmojiFilename:(NSString *)filename +{ + NSArray *components = [filename componentsSeparatedByString:@"-"]; + NSMutableArray *marr = [NSMutableArray array]; + for (NSString *string in components) { + NSString *unicodeChar = [NSString unicodeCharacterFromHexString:string]; + if (unicodeChar) { + [marr addObject:unicodeChar]; + } + } + + return [marr componentsJoinedByString:@""]; +} + ++ (NSString *)unicodeCharacterFromHexString:(NSString *)hexString +{ + NSScanner *scanner = [NSScanner scannerWithString:hexString]; + unsigned long long hex = 0; + BOOL success = [scanner scanHexLongLong:&hex]; + if (!success) { + return nil; + } + return [[NSString alloc] initWithBytes:&hex length:4 encoding:NSUTF32LittleEndianStringEncoding]; +} + +// Taken from AFNetworking's AFPercentEscapedQueryStringPairMemberFromStringWithEncoding +- (NSString *)wpkit_stringByUrlEncoding +{ + NSMutableCharacterSet * allowedCharacterSet = [[NSCharacterSet URLQueryAllowedCharacterSet] mutableCopy]; + NSString *charactersToLeaveUnescaped = @"[]."; + [allowedCharacterSet addCharactersInString:charactersToLeaveUnescaped]; + return [self stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacterSet]; +} + +/* + * Uses a RegEx to strip all HTML tags from a string and unencode entites + */ +- (NSString *)wpkit_stringByStrippingHTML +{ + return [self stringByReplacingOccurrencesOfString:@"<[^>]+>" withString:@"" options:NSRegularExpressionSearch range:NSMakeRange(0, self.length)]; +} + +// A method to truncate a string at a predetermined length and append ellipsis to the end + +- (NSString *)wpkit_stringByEllipsizingWithMaxLength:(NSInteger)lengthlimit preserveWords:(BOOL)preserveWords +{ + NSInteger currentLength = [self length]; + NSString *result = @""; + NSString *temp = @""; + + if (currentLength <= lengthlimit) { //If the string is already within limits + return self; + } else if (lengthlimit > 0) { //If the string is longer than the limit, and the limit is larger than 0. + + NSInteger newLimitWithoutEllipsis = lengthlimit - [Ellipsis length]; + + if (preserveWords) { + + NSArray *wordsSeperated = [self tokenize]; + + if ([wordsSeperated count] == 1) { // If this is a long word then we disregard preserveWords property. + return [NSString stringWithFormat:@"%@%@", [self substringToIndex:newLimitWithoutEllipsis], Ellipsis]; + } + + for (NSString *word in wordsSeperated) { + + if ([temp isEqualToString:@""]) { + temp = word; + } else { + temp = [NSString stringWithFormat:@"%@%@", temp, word]; + } + + if ([temp length] <= newLimitWithoutEllipsis) { + result = [temp copy]; + } else { + return [NSString stringWithFormat:@"%@%@",result,Ellipsis]; + } + } + } else { + return [NSString stringWithFormat:@"%@%@", [self substringToIndex:newLimitWithoutEllipsis], Ellipsis]; + } + + } else { //if the limit is 0. + return @""; + } + + return self; +} + +- (NSArray *)tokenize +{ + CFLocaleRef locale = CFLocaleCopyCurrent(); + CFRange stringRange = CFRangeMake(0, [self length]); + + CFStringTokenizerRef tokenizer = CFStringTokenizerCreate(kCFAllocatorDefault, + (CFStringRef)self, + stringRange, + kCFStringTokenizerUnitWordBoundary, + locale); + + CFStringTokenizerTokenType tokenType = CFStringTokenizerAdvanceToNextToken(tokenizer); + + NSMutableArray *tokens = [NSMutableArray new]; + + while (tokenType != kCFStringTokenizerTokenNone) { + stringRange = CFStringTokenizerGetCurrentTokenRange(tokenizer); + NSString *token = [self substringWithRange:NSMakeRange(stringRange.location, stringRange.length)]; + [tokens addObject:token]; + tokenType = CFStringTokenizerAdvanceToNextToken(tokenizer); + } + + CFRelease(locale); + CFRelease(tokenizer); + + return tokens; +} + +- (bool)wpkit_isEmpty { + return self.length == 0; +} + +@end + +@implementation NSString (WPKitNumericValueHack) + +- (NSNumber *)wpkit_numericValue { + return [NSNumber numberWithUnsignedLongLong:[self longLongValue]]; +} + +@end + +@implementation NSObject (WPKitNumericValueHack) +- (NSNumber *)wpkit_numericValue { + if ([self isKindOfClass:[NSNumber class]]) { + return (NSNumber *)self; + } + return nil; +} +@end diff --git a/Sources/WordPressShared/NSString+Summary.swift b/Sources/WordPressShared/NSString+Summary.swift new file mode 100644 index 00000000..ca8f8798 --- /dev/null +++ b/Sources/WordPressShared/NSString+Summary.swift @@ -0,0 +1,79 @@ +import Foundation + +/// This is an extension to NSString that provides logic to summarize HTML content, +/// and convert HTML into plain text. +/// +extension NSString { + + static let PostDerivedSummaryLength = 150 + + /// Create a summary for the post based on the post's content. + /// + /// - Returns: A summary for the post. + /// + @objc + public func wpkit_summarized() -> String { + let characterSet = CharacterSet(charactersIn: "\n") + + return (self as String).strippingGutenbergContentForExcerpt() + .strippingShortcodes() + .makePlainText() + .trimmingCharacters(in: characterSet) + .wpkit_stringByEllipsizing(withMaxLength: NSString.PostDerivedSummaryLength, preserveWords: true) + } +} + +private extension String { + func makePlainText() -> String { + let characterSet = NSCharacterSet.whitespacesAndNewlines + + return self.wpkit_stringByStrippingHTML() + .wpkit_stringByDecodingXMLCharacters() + .trimmingCharacters(in: characterSet) + } + + /// Creates a new string by stripping all shortcodes from this string. + /// + func strippingShortcodes() -> String { + let pattern = "\\[[^\\]]+\\]" + + return removingMatches(pattern: pattern, options: .caseInsensitive) + } + + /// This method is the main entry point to generate excerpts for Gutenberg content. + /// + func strippingGutenbergContentForExcerpt() -> String { + return strippingGutenbergGalleries().strippingGutenbergVideoPress() + } + + /// Strips Gutenberg galleries from strings. + /// + func strippingGutenbergGalleries() -> String { + let pattern = "(?s)" + + return removingMatches(pattern: pattern, options: .caseInsensitive) + } + + /// Strips VideoPress references from Gutenberg VideoPress and Video blocks. + /// + func strippingGutenbergVideoPress() -> String { + let pattern = "(?s)\n?" + + return removingMatches(pattern: pattern, options: .caseInsensitive) + } + + /// Creates a new string by removing all matches of the specified regex. + /// + func removingMatches(pattern: String, options: NSRegularExpression.Options = []) -> String { + let range = NSRange(location: 0, length: self.utf16.count) + let regex: NSRegularExpression + + do { + regex = try NSRegularExpression(pattern: pattern, options: options) + } catch { + return self + } + + return regex.stringByReplacingMatches(in: self, options: .reportCompletion, range: range, withTemplate: "") + } +} diff --git a/Sources/WordPressShared/NSString+XMLExtensions.h b/Sources/WordPressShared/NSString+XMLExtensions.h new file mode 100644 index 00000000..046cc7a6 --- /dev/null +++ b/Sources/WordPressShared/NSString+XMLExtensions.h @@ -0,0 +1,10 @@ +#import + +@interface NSString (XMLExtensions) + ++ (NSString *)wpkit_encodeXMLCharactersIn : (NSString *)source; ++ (NSString *)wpkit_decodeXMLCharactersIn : (NSString *)source; +- (NSString *)wpkit_stringByDecodingXMLCharacters; +- (NSString *)wpkit_stringByEncodingXMLCharacters; + +@end diff --git a/Sources/WordPressShared/NSString+XMLExtensions.m b/Sources/WordPressShared/NSString+XMLExtensions.m new file mode 100644 index 00000000..0738555d --- /dev/null +++ b/Sources/WordPressShared/NSString+XMLExtensions.m @@ -0,0 +1,400 @@ +// Adapted from MWFeedParser +// https://github.com/mwaterfall/MWFeedParser Copyright (c) 2010 Michael Waterfall + +#import "NSString+XMLExtensions.h" + + +typedef struct { + __unsafe_unretained NSString *escapeSequence; + unichar uchar; +} HTMLEscapeMap; + + +// Taken from http://www.w3.org/TR/xhtml1/dtds.html#a_dtd_Special_characters +// Ordered by uchar lowest to highest for bsearching +static HTMLEscapeMap gAsciiHTMLEscapeMap[] = { + // A.2.2. Special characters + { @""", 34 }, + { @"&", 38 }, + { @"'", 39 }, + { @"<", 60 }, + { @">", 62 }, + + // A.2.1. Latin-1 characters + { @" ", 160 }, + { @"¡", 161 }, + { @"¢", 162 }, + { @"£", 163 }, + { @"¤", 164 }, + { @"¥", 165 }, + { @"¦", 166 }, + { @"§", 167 }, + { @"¨", 168 }, + { @"©", 169 }, + { @"ª", 170 }, + { @"«", 171 }, + { @"¬", 172 }, + { @"­", 173 }, + { @"®", 174 }, + { @"¯", 175 }, + { @"°", 176 }, + { @"±", 177 }, + { @"²", 178 }, + { @"³", 179 }, + { @"´", 180 }, + { @"µ", 181 }, + { @"¶", 182 }, + { @"·", 183 }, + { @"¸", 184 }, + { @"¹", 185 }, + { @"º", 186 }, + { @"»", 187 }, + { @"¼", 188 }, + { @"½", 189 }, + { @"¾", 190 }, + { @"¿", 191 }, + { @"À", 192 }, + { @"Á", 193 }, + { @"Â", 194 }, + { @"Ã", 195 }, + { @"Ä", 196 }, + { @"Å", 197 }, + { @"Æ", 198 }, + { @"Ç", 199 }, + { @"È", 200 }, + { @"É", 201 }, + { @"Ê", 202 }, + { @"Ë", 203 }, + { @"Ì", 204 }, + { @"Í", 205 }, + { @"Î", 206 }, + { @"Ï", 207 }, + { @"Ð", 208 }, + { @"Ñ", 209 }, + { @"Ò", 210 }, + { @"Ó", 211 }, + { @"Ô", 212 }, + { @"Õ", 213 }, + { @"Ö", 214 }, + { @"×", 215 }, + { @"Ø", 216 }, + { @"Ù", 217 }, + { @"Ú", 218 }, + { @"Û", 219 }, + { @"Ü", 220 }, + { @"Ý", 221 }, + { @"Þ", 222 }, + { @"ß", 223 }, + { @"à", 224 }, + { @"á", 225 }, + { @"â", 226 }, + { @"ã", 227 }, + { @"ä", 228 }, + { @"å", 229 }, + { @"æ", 230 }, + { @"ç", 231 }, + { @"è", 232 }, + { @"é", 233 }, + { @"ê", 234 }, + { @"ë", 235 }, + { @"ì", 236 }, + { @"í", 237 }, + { @"î", 238 }, + { @"ï", 239 }, + { @"ð", 240 }, + { @"ñ", 241 }, + { @"ò", 242 }, + { @"ó", 243 }, + { @"ô", 244 }, + { @"õ", 245 }, + { @"ö", 246 }, + { @"÷", 247 }, + { @"ø", 248 }, + { @"ù", 249 }, + { @"ú", 250 }, + { @"û", 251 }, + { @"ü", 252 }, + { @"ý", 253 }, + { @"þ", 254 }, + { @"ÿ", 255 }, + + // A.2.2. Special characters cont'd + { @"Œ", 338 }, + { @"œ", 339 }, + { @"Š", 352 }, + { @"š", 353 }, + { @"Ÿ", 376 }, + + // A.2.3. Symbols + { @"ƒ", 402 }, + + // A.2.2. Special characters cont'd + { @"ˆ", 710 }, + { @"˜", 732 }, + + // A.2.3. Symbols cont'd + { @"Α", 913 }, + { @"Β", 914 }, + { @"Γ", 915 }, + { @"Δ", 916 }, + { @"Ε", 917 }, + { @"Ζ", 918 }, + { @"Η", 919 }, + { @"Θ", 920 }, + { @"Ι", 921 }, + { @"Κ", 922 }, + { @"Λ", 923 }, + { @"Μ", 924 }, + { @"Ν", 925 }, + { @"Ξ", 926 }, + { @"Ο", 927 }, + { @"Π", 928 }, + { @"Ρ", 929 }, + { @"Σ", 931 }, + { @"Τ", 932 }, + { @"Υ", 933 }, + { @"Φ", 934 }, + { @"Χ", 935 }, + { @"Ψ", 936 }, + { @"Ω", 937 }, + { @"α", 945 }, + { @"β", 946 }, + { @"γ", 947 }, + { @"δ", 948 }, + { @"ε", 949 }, + { @"ζ", 950 }, + { @"η", 951 }, + { @"θ", 952 }, + { @"ι", 953 }, + { @"κ", 954 }, + { @"λ", 955 }, + { @"μ", 956 }, + { @"ν", 957 }, + { @"ξ", 958 }, + { @"ο", 959 }, + { @"π", 960 }, + { @"ρ", 961 }, + { @"ς", 962 }, + { @"σ", 963 }, + { @"τ", 964 }, + { @"υ", 965 }, + { @"φ", 966 }, + { @"χ", 967 }, + { @"ψ", 968 }, + { @"ω", 969 }, + { @"ϑ", 977 }, + { @"ϒ", 978 }, + { @"ϖ", 982 }, + + // A.2.2. Special characters cont'd + { @" ", 8194 }, + { @" ", 8195 }, + { @" ", 8201 }, + { @"‌", 8204 }, + { @"‍", 8205 }, + { @"‎", 8206 }, + { @"‏", 8207 }, + { @"–", 8211 }, + { @"—", 8212 }, + { @"‘", 8216 }, + { @"’", 8217 }, + { @"‚", 8218 }, + { @"“", 8220 }, + { @"”", 8221 }, + { @"„", 8222 }, + { @"†", 8224 }, + { @"‡", 8225 }, + // A.2.3. Symbols cont'd + { @"•", 8226 }, + { @"…", 8230 }, + + // A.2.2. Special characters cont'd + { @"‰", 8240 }, + + // A.2.3. Symbols cont'd + { @"′", 8242 }, + { @"″", 8243 }, + + // A.2.2. Special characters cont'd + { @"‹", 8249 }, + { @"›", 8250 }, + + // A.2.3. Symbols cont'd + { @"‾", 8254 }, + { @"⁄", 8260 }, + + // A.2.2. Special characters cont'd + { @"€", 8364 }, + + // A.2.3. Symbols cont'd + { @"ℑ", 8465 }, + { @"℘", 8472 }, + { @"ℜ", 8476 }, + { @"™", 8482 }, + { @"ℵ", 8501 }, + { @"←", 8592 }, + { @"↑", 8593 }, + { @"→", 8594 }, + { @"↓", 8595 }, + { @"↔", 8596 }, + { @"↵", 8629 }, + { @"⇐", 8656 }, + { @"⇑", 8657 }, + { @"⇒", 8658 }, + { @"⇓", 8659 }, + { @"⇔", 8660 }, + { @"∀", 8704 }, + { @"∂", 8706 }, + { @"∃", 8707 }, + { @"∅", 8709 }, + { @"∇", 8711 }, + { @"∈", 8712 }, + { @"∉", 8713 }, + { @"∋", 8715 }, + { @"∏", 8719 }, + { @"∑", 8721 }, + { @"−", 8722 }, + { @"∗", 8727 }, + { @"√", 8730 }, + { @"∝", 8733 }, + { @"∞", 8734 }, + { @"∠", 8736 }, + { @"∧", 8743 }, + { @"∨", 8744 }, + { @"∩", 8745 }, + { @"∪", 8746 }, + { @"∫", 8747 }, + { @"∴", 8756 }, + { @"∼", 8764 }, + { @"≅", 8773 }, + { @"≈", 8776 }, + { @"≠", 8800 }, + { @"≡", 8801 }, + { @"≤", 8804 }, + { @"≥", 8805 }, + { @"⊂", 8834 }, + { @"⊃", 8835 }, + { @"⊄", 8836 }, + { @"⊆", 8838 }, + { @"⊇", 8839 }, + { @"⊕", 8853 }, + { @"⊗", 8855 }, + { @"⊥", 8869 }, + { @"⋅", 8901 }, + { @"⌈", 8968 }, + { @"⌉", 8969 }, + { @"⌊", 8970 }, + { @"⌋", 8971 }, + { @"⟨", 9001 }, + { @"⟩", 9002 }, + { @"◊", 9674 }, + { @"♠", 9824 }, + { @"♣", 9827 }, + { @"♥", 9829 }, + { @"♦", 9830 } +}; + + +@implementation NSString (XMLExtensions) + ++ (NSString *)wpkit_encodeXMLCharactersIn : (NSString *)source { + if (![source isKindOfClass:[NSString class]] || !source) + return @""; + + NSString *result = [NSString stringWithString:source]; + + // NOTE: we use unicode entities instead of & > < since some weird hosts (powweb, fatcow, and cousins) + // have a weird PHP/libxml2 combination that ignores regular entities + if ([result rangeOfString:@"&"].location != NSNotFound) + result = [[result componentsSeparatedByString:@"&"] componentsJoinedByString:@"&"]; + + if ([result rangeOfString:@"<"].location != NSNotFound) + result = [[result componentsSeparatedByString:@"<"] componentsJoinedByString:@"<"]; + + if ([result rangeOfString:@">"].location != NSNotFound) + result = [[result componentsSeparatedByString:@">"] componentsJoinedByString:@">"]; + + return result; +} + + ++ (NSString *) wpkit_decodeXMLCharactersIn:(NSString *)original { + if (![original isKindOfClass:[NSString class]] || !original) + return @""; + + NSString *source = [NSString stringWithString:original]; + + NSRange range = NSMakeRange(0, [source length]); + NSRange subrange = [source rangeOfString:@"&" options:NSBackwardsSearch range:range]; + + // if no ampersands, we've got a quick way out + if (subrange.length == 0) return source; + NSMutableString *finalString = [NSMutableString stringWithString:source]; + do { + NSRange semiColonRange = NSMakeRange(subrange.location, NSMaxRange(range) - subrange.location); + semiColonRange = [source rangeOfString:@";" options:0 range:semiColonRange]; + range = NSMakeRange(0, subrange.location); + // if we don't find a semicolon in the range, we don't have a sequence + if (semiColonRange.location == NSNotFound) { + continue; + } + NSRange escapeRange = NSMakeRange(subrange.location, semiColonRange.location - subrange.location + 1); + NSString *escapeString = [source substringWithRange:escapeRange]; + NSUInteger length = [escapeString length]; + // a squence must be longer than 3 (<) and less than 11 (ϑ) + if (length > 3 && length < 11) { + if ([escapeString characterAtIndex:1] == '#') { + unichar char2 = [escapeString characterAtIndex:2]; + if (char2 == 'x' || char2 == 'X') { + // Hex escape squences £ + NSString *hexSequence = [escapeString substringWithRange:NSMakeRange(3, length - 4)]; + NSScanner *scanner = [NSScanner scannerWithString:hexSequence]; + unsigned value; + if ([scanner scanHexInt:&value] && + value < USHRT_MAX && + value > 0 + && [scanner scanLocation] == length - 4) { + unichar uchar = value; + NSString *charString = [NSString stringWithCharacters:&uchar length:1]; + [finalString replaceCharactersInRange:escapeRange withString:charString]; + } + + } else { + // Decimal Sequences { + NSString *numberSequence = [escapeString substringWithRange:NSMakeRange(2, length - 3)]; + NSScanner *scanner = [NSScanner scannerWithString:numberSequence]; + int value; + if ([scanner scanInt:&value] && + value < USHRT_MAX && + value > 0 + && [scanner scanLocation] == length - 3) { + unichar uchar = value; + NSString *charString = [NSString stringWithCharacters:&uchar length:1]; + [finalString replaceCharactersInRange:escapeRange withString:charString]; + } + } + } else { + // "standard" sequences + for (unsigned i = 0; i < sizeof(gAsciiHTMLEscapeMap) / sizeof(HTMLEscapeMap); ++i) { + if ([escapeString isEqualToString:gAsciiHTMLEscapeMap[i].escapeSequence]) { + [finalString replaceCharactersInRange:escapeRange withString:[NSString stringWithCharacters:&gAsciiHTMLEscapeMap[i].uchar length:1]]; + break; + } + } + } + } + + } while ((subrange = [source rangeOfString:@"&" options:NSBackwardsSearch range:range]).length != 0); + + return finalString; +} + +- (NSString *)wpkit_stringByDecodingXMLCharacters { + return [NSString wpkit_decodeXMLCharactersIn:self]; +} +- (NSString *)wpkit_stringByEncodingXMLCharacters { + return [NSString wpkit_encodeXMLCharactersIn:self]; +} + + +@end diff --git a/Sources/WordPressShared/Secret.swift b/Sources/WordPressShared/Secret.swift new file mode 100644 index 00000000..66b5a8f0 --- /dev/null +++ b/Sources/WordPressShared/Secret.swift @@ -0,0 +1,49 @@ +import Foundation + +/// Wraps a value that contains sensitive information to prevent accidental logging +/// +/// Usage example +/// +/// ``` +/// let password = Secret("my secret password") +/// print(password) // Prints "--redacted--" +/// print(password.secretValue) // Prints "my secret password" +/// ``` +/// +public struct Secret { + public let secretValue: T + + public init(_ secretValue: T) { + self.secretValue = secretValue + } +} + +extension Secret: RawRepresentable { + public typealias RawValue = T + + public init?(rawValue: Self.RawValue) { + self.init(rawValue) + } + + public var rawValue: T { + return secretValue + } +} + +extension Secret: CustomStringConvertible, CustomDebugStringConvertible, CustomReflectable { + private static var redacted: String { + return "--redacted--" + } + + public var description: String { + return Secret.redacted + } + + public var debugDescription: String { + return Secret.redacted + } + + public var customMirror: Mirror { + return Mirror(reflecting: Secret.redacted) + } +} diff --git a/Sources/WordPressShared/String+Helpers.swift b/Sources/WordPressShared/String+Helpers.swift new file mode 100644 index 00000000..cc73aa2f --- /dev/null +++ b/Sources/WordPressShared/String+Helpers.swift @@ -0,0 +1,167 @@ +import Foundation + +extension String { + func stringByDecodingXMLCharacters() -> String { + return NSString.wpkit_decodeXMLCharacters(in: self) + } + + func stringByEncodingXMLCharacters() -> String { + return NSString.wpkit_encodeXMLCharacters(in: self) + } + + func trim() -> String { + return trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) + } + + /// Returns `self` if not empty, or `nil` otherwise + /// + func nonEmptyString() -> String? { + return isEmpty ? nil : self + } + + /// Returns a string without the character at the specified index. + /// This is a non-mutating version of `String.remove(at:)`. + func removing(at index: Index) -> String { + var copy = self + copy.remove(at: index) + return copy + } + + /// Returns a count of valid text characters. + /// - Note : This implementation is influenced by `-wordCount` in `NSString+Helpers`. + var characterCount: Int { + var charCount = 0 + + if isEmpty == false { + let textRange = startIndex.. String { + var copy = self + copy.removePrefix(prefix) + return copy + } + + /// Removes the prefix from the string that matches the given pattern, if any. + /// + /// Calling this method might invalidate any existing indices for use with this string. + /// + /// - Parameters: + /// - pattern: The regular expression pattern to search for. Avoid using `^`. + /// - options: The options applied to the regular expression during matching. + /// + /// - Throws: an error if it the pattern is not a valid regular expression. + /// + mutating func removePrefix(pattern: String, options: NSRegularExpression.Options = []) throws { + let regexp = try NSRegularExpression(pattern: "^\(pattern)", options: options) + let fullRange = NSRange(location: 0, length: (self as NSString).length) + if let match = regexp.firstMatch(in: self, options: [], range: fullRange) { + let matchRange = match.range + self = (self as NSString).replacingCharacters(in: matchRange, with: "") + } + } + + /// Returns a string without the prefix that matches the given pattern, if it exists. + /// + /// - Parameters: + /// - pattern: The regular expression pattern to search for. Avoid using `^`. + /// - options: The options applied to the regular expression during matching. + /// + /// - Throws: an error if it the pattern is not a valid regular expression. + /// + func removingPrefix(pattern: String, options: NSRegularExpression.Options = []) throws -> String { + var copy = self + try copy.removePrefix(pattern: pattern, options: options) + return copy + } +} + +// MARK: - Suffix removal + +extension String { + /// Removes the given suffix from the string, if exists. + /// + /// Calling this method might invalidate any existing indices for use with this string. + /// + /// - Parameters: + /// - suffix: A possible suffix to remove from this string. + /// + mutating func removeSuffix(_ suffix: String) { + if let suffixRange = range(of: suffix, options: [.backwards]), suffixRange.upperBound == endIndex { + removeSubrange(suffixRange) + } + } + + /// Returns a string with the given suffix removed, if it exists. + /// + /// - Parameters: + /// - suffix: A possible suffix to remove from this string. + /// + func removingSuffix(_ suffix: String) -> String { + var copy = self + copy.removeSuffix(suffix) + return copy + } + + /// Removes the suffix from the string that matches the given pattern, if any. + /// + /// Calling this method might invalidate any existing indices for use with this string. + /// + /// - Parameters: + /// - pattern: The regular expression pattern to search for. Avoid using `$`. + /// - options: The options applied to the regular expression during matching. + /// + /// - Throws: an error if it the pattern is not a valid regular expression. + /// + mutating func removeSuffix(pattern: String, options: NSRegularExpression.Options = []) throws { + let regexp = try NSRegularExpression(pattern: "\(pattern)$", options: options) + let fullRange = NSRange(location: 0, length: (self as NSString).length) + if let match = regexp.firstMatch(in: self, options: [], range: fullRange) { + let matchRange = match.range + self = (self as NSString).replacingCharacters(in: matchRange, with: "") + } + } + + /// Returns a string without the suffix that matches the given pattern, if it exists. + /// + /// - Parameters: + /// - pattern: The regular expression pattern to search for. Avoid using `$`. + /// - options: The options applied to the regular expression during matching. + /// + /// - Throws: an error if it the pattern is not a valid regular expression. + /// + func removingSuffix(pattern: String, options: NSRegularExpression.Options = []) throws -> String { + var copy = self + try copy.removeSuffix(pattern: pattern, options: options) + return copy + } +} diff --git a/Sources/WordPressShared/WPKitDateUtils.h b/Sources/WordPressShared/WPKitDateUtils.h new file mode 100644 index 00000000..4cd6a337 --- /dev/null +++ b/Sources/WordPressShared/WPKitDateUtils.h @@ -0,0 +1,8 @@ +#import + +@interface WPKitDateUtils : NSObject + ++ (NSDate *)dateFromISOString:(NSString *)isoString; ++ (NSString *)isoStringFromDate:(NSDate *)date; + +@end diff --git a/Sources/WordPressShared/WPKitDateUtils.m b/Sources/WordPressShared/WPKitDateUtils.m new file mode 100644 index 00000000..02f561cf --- /dev/null +++ b/Sources/WordPressShared/WPKitDateUtils.m @@ -0,0 +1,37 @@ +#import "WPKitDateUtils.h" + +@implementation WPKitDateUtils + ++ (NSDate *)dateFromISOString:(NSString *)dateString +{ + NSArray *formats = @[@"yyyy-MM-dd'T'HH:mm:ssZZZZZ", @"yyyy-MM-dd HH:mm:ss"]; + NSDate *date = nil; + if ([dateString length] == 25) { + NSRange rng = [dateString rangeOfString:@":" options:NSBackwardsSearch range:NSMakeRange(20, 5)]; + if (rng.location != NSNotFound) { + dateString = [dateString stringByReplacingCharactersInRange:rng withString:@""]; + } + } + NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; + dateFormatter.locale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"]; + dateFormatter.timeZone = [NSTimeZone timeZoneWithName:@"GMT"]; + for (NSString *dateFormat in formats) { + [dateFormatter setDateFormat:dateFormat]; + date = [dateFormatter dateFromString:dateString]; + if (date){ + return date; + } + } + return date; +} + ++ (NSString *)isoStringFromDate:(NSDate *)date +{ + NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; + dateFormatter.locale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"]; + dateFormatter.timeZone = [NSTimeZone timeZoneWithName:@"GMT"]; + [dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ssZZZZZ"]; + return [dateFormatter stringFromDate:date]; +} + +@end diff --git a/Sources/WordPressShared/WPMapFilterReduce.h b/Sources/WordPressShared/WPMapFilterReduce.h new file mode 100644 index 00000000..c7968cf9 --- /dev/null +++ b/Sources/WordPressShared/WPMapFilterReduce.h @@ -0,0 +1,22 @@ +#import + +typedef id (^WPKitMapBlock)(id obj); +typedef BOOL (^WPKitFilterBlock)(id obj); + +@interface NSArray (WPKitMapFilterReduce) + +/** + Transforms values in an array + + The resulting array will include the results of calling mapBlock for each of + the receiver array objects. If mapBlock returns nil that value will be missing + from the resulting array. + */ +- (NSArray *)wpkit_map:(WPKitMapBlock)mapBlock; + +/** + Filters an array to only include values that satisfy the filter block + */ +- (NSArray *)wpkit_filter:(WPKitFilterBlock)filterBlock; + +@end diff --git a/Sources/WordPressShared/WPMapFilterReduce.m b/Sources/WordPressShared/WPMapFilterReduce.m new file mode 100644 index 00000000..1e8b7683 --- /dev/null +++ b/Sources/WordPressShared/WPMapFilterReduce.m @@ -0,0 +1,28 @@ +#import "WPMapFilterReduce.h" + +@implementation NSArray (WPKitMapFilterReduce) + +- (NSArray *)wpkit_map:(WPKitMapBlock)mapBlock +{ + NSMutableArray *results = [NSMutableArray arrayWithCapacity:self.count]; + for (id obj in self) { + id objectToAdd = mapBlock(obj); + if (objectToAdd) { + [results addObject:objectToAdd]; + } + } + return [NSArray arrayWithArray:results]; +} + +- (NSArray *)wpkit_filter:(WPKitFilterBlock)filterBlock +{ + NSMutableArray *results = [NSMutableArray arrayWithCapacity:self.count]; + for (id obj in self) { + if (filterBlock(obj)) { + [results addObject:obj]; + } + } + return [NSArray arrayWithArray:results]; +} + +@end diff --git a/Sources/WordPressShared/WordPressComLanguageDatabase.swift b/Sources/WordPressShared/WordPressComLanguageDatabase.swift new file mode 100644 index 00000000..7055fe67 --- /dev/null +++ b/Sources/WordPressShared/WordPressComLanguageDatabase.swift @@ -0,0 +1,367 @@ +import Foundation + +/// This helper class allows us to map WordPress.com LanguageID's into human readable language strings. +/// +class WordPressComLanguageDatabase: NSObject { + // MARK: - Properties + + /// Languages considered 'popular' + /// + let popular: [Language] + + /// Every supported language + /// + let all: [Language] + + /// Returns both, Popular and All languages, grouped + /// + let grouped: [[Language]] + + + // MARK: - Methods + + /// Designated Initializer: will load the languages contained within the `Languages.json` file. + /// + override init() { + // Parse the json file + let raw = languagesJSON.data(using: .utf8)! + let parsed = try! JSONSerialization.jsonObject(with: raw, options: [.mutableContainers, .mutableLeaves]) as? NSDictionary + + // Parse All + Popular: All doesn't contain Popular. Otherwise the json would have dupe data. Right? + let parsedAll = Language.fromArray(parsed![Keys.all] as! [[String: Any]]) + let parsedPopular = Language.fromArray(parsed![Keys.popular] as! [[String: Any]]) + let merged = parsedAll + parsedPopular + + // Done! + popular = parsedPopular + all = merged.sorted { $0.name < $1.name } + grouped = [popular] + [all] + } + + + /// Returns the Human Readable name for a given Language Identifier + /// + /// - Parameter languageId: The Identifier of the language. + /// + /// - Returns: A string containing the language name, or an empty string, in case it wasn't found. + /// + @objc func nameForLanguageWithId(_ languageId: Int) -> String { + return find(id: languageId)?.name ?? "" + } + + /// Returns the Language with a given Language Identifier + /// + /// - Parameter id: The Identifier of the language. + /// + /// - Returns: The language with the matching Identifier, or nil, in case it wasn't found. + /// + func find(id: Int) -> Language? { + return all.first(where: { $0.id == id }) + } + + /// Returns the current device language as the corresponding WordPress.com language ID. + /// If the language is not supported, it returns 1 (English). + /// + /// This is a wrapper for Objective-C, Swift code should use deviceLanguage directly. + /// + @objc(deviceLanguageId) + func deviceLanguageIdNumber() -> NSNumber { + return NSNumber(value: deviceLanguage.id) + } + + /// Returns the slug string for the current device language. + /// If the language is not supported, it returns "en" (English). + /// + /// This is a wrapper for Objective-C, Swift code should use deviceLanguage directly. + /// + @objc(deviceLanguageSlug) + func deviceLanguageSlugString() -> String { + return deviceLanguage.slug + } + + /// Returns the current device language as the corresponding WordPress.com language. + /// If the language is not supported, it returns English. + /// + var deviceLanguage: Language { + let variants = LanguageTagVariants(string: deviceLanguageCode) + for variant in variants { + if let match = self.languageWithSlug(variant) { + return match + } + } + return languageWithSlug("en")! + } + + /// Searches for a WordPress.com language that matches a language tag. + /// + fileprivate func languageWithSlug(_ slug: String) -> Language? { + let search = languageCodeReplacements[slug] ?? slug + + // Use lazy evaluation so we stop filtering as soon as we got the first match + return all.lazy.filter({ $0.slug == search }).first + } + + /// Overrides the device language. For testing purposes only. + /// + @objc func _overrideDeviceLanguageCode(_ code: String) { + deviceLanguageCode = code.lowercased() + } + + // MARK: - Nested Classes + + /// Represents a Language supported by WordPress.com + /// + class Language: Equatable { + /// Language Unique Identifier + /// + let id: Int + + /// Human readable Language name + /// + let name: String + + /// Language's Slug String + /// + let slug: String + + /// Localized description for the current language + /// + var description: String { + return (Locale.current as NSLocale).displayName(forKey: NSLocale.Key.identifier, value: slug) ?? name + } + + + + /// Designated initializer. Will fail if any of the required properties is missing + /// + init?(dict: [String: Any]) { + guard let unwrappedId = (dict[Keys.identifier] as? NSNumber)?.intValue, + let unwrappedSlug = dict[Keys.slug] as? String, + let unwrappedName = dict[Keys.name] as? String else { + id = Int.min + name = String() + slug = String() + return nil + } + + id = unwrappedId + name = unwrappedName + slug = unwrappedSlug + } + + + /// Given an array of raw languages, will return a parsed array. + /// + static func fromArray(_ array: [[String: Any]] ) -> [Language] { + return array.compactMap { + return Language(dict: $0) + } + } + + static func == (lhs: Language, rhs: Language) -> Bool { + return lhs.id == rhs.id + } + } + + // MARK: - Private Variables + + /// The device's current preferred language, or English if there's no preferred language. + /// + fileprivate lazy var deviceLanguageCode: String = { + return NSLocale.preferredLanguages.first?.lowercased() ?? "en" + }() + + + // MARK: - Private Constants + fileprivate let filename = "Languages" + + // (@koke 2016-04-29) I'm not sure how correct this mapping is, but it matches + // what we do for the app translations, so they will at least be consistent + fileprivate let languageCodeReplacements: [String: String] = [ + "zh-hans": "zh-cn", + "zh-hant": "zh-tw" + ] + + + // MARK: - Private Nested Structures + + /// Keys used to parse the raw languages. + /// + fileprivate struct Keys { + static let popular = "popular" + static let all = "all" + static let identifier = "i" + static let slug = "s" + static let name = "n" + } +} + +/// Provides a sequence of language tags from the specified string, from more to less specific +/// For instance, "zh-Hans-HK" will yield `["zh-Hans-HK", "zh-Hans", "zh"]` +/// +private struct LanguageTagVariants: Sequence { + let string: String + + func makeIterator() -> AnyIterator { + var components = string.components(separatedBy: "-") + return AnyIterator { + guard !components.isEmpty else { + return nil + } + + let current = components.joined(separator: "-") + components.removeLast() + + return current + } + } +} + +private let languagesJSON = """ +{ + "popular" : [ + { "i": 1, "s": "en", "n": "English" }, + { "i": 19, "s": "es", "n": "Español" }, + { "i": 438, "s": "pt-br", "n": "Português do Brasil" }, + { "i": 15, "s": "de", "n": "Deutsch" }, + { "i": 24, "s": "fr", "n": "Français" }, + { "i": 29, "s": "he", "n": "עברית" }, + { "i": 36, "s": "ja", "n": "日本語" }, + { "i": 35, "s": "it", "n": "Italiano" }, + { "i": 49, "s": "nl", "n": "Nederlands" }, + { "i": 62, "s": "ru", "n": "Русский" }, + { "i": 78, "s": "tr", "n": "Türkçe" }, + { "i": 33, "s": "id", "n": "Bahasa Indonesia" }, + { "i": 449, "s": "zh-cn", "n": "中文(简体)" }, + { "i": 452, "s": "zh-tw", "n": "中文(繁體)" }, + { "i": 40, "s": "ko", "n": "한국어" } + ], + "all" : [ + { "i": 2, "s": "af", "n": "Afrikaans" }, + { "i": 418, "s": "als", "n": "Alemannisch" }, + { "i": 481, "s": "am", "n": "Amharic" }, + { "i": 3, "s": "ar", "n": "العربية" }, + { "i": 419, "s": "arc", "n": "ܕܥܒܪܸܝܛ" }, + { "i": 4, "s": "as", "n": "অসমীয়া" }, + { "i": 420, "s": "ast", "n": "Asturianu" }, + { "i": 421, "s": "av", "n": "Авар" }, + { "i": 422, "s": "ay", "n": "Aymar" }, + { "i": 79, "s": "az", "n": "Azərbaycan" }, + { "i": 423, "s": "ba", "n": "Башҡорт" }, + { "i": 5, "s": "be", "n": "Беларуская" }, + { "i": 6, "s": "bg", "n": "Български" }, + { "i": 7, "s": "bm", "n": "Bamanankan" }, + { "i": 8, "s": "bn", "n": "বাংলা" }, + { "i": 9, "s": "bo", "n": "བོད་ཡིག" }, + { "i": 424, "s": "br", "n": "Brezhoneg" }, + { "i": 454, "s": "bs", "n": "Bosanski" }, + { "i": 10, "s": "ca", "n": "Català" }, + { "i": 425, "s": "ce", "n": "Нохчийн" }, + { "i": 11, "s": "cs", "n": "Česky" }, + { "i": 12, "s": "csb", "n": "Kaszëbsczi" }, + { "i": 426, "s": "cv", "n": "Чӑваш" }, + { "i": 13, "s": "cy", "n": "Cymraeg" }, + { "i": 14, "s": "da", "n": "Dansk" }, + { "i": 427, "s": "dv", "n": "Divehi" }, + { "i": 16, "s": "dz", "n": "ཇོང་ཁ" }, + { "i": 17, "s": "el", "n": "Ελληνικά" }, + { "i": 468, "s": "el-po", "n": "Greek-polytonic" }, + { "i": 18, "s": "eo", "n": "Esperanto" }, + { "i": 20, "s": "et", "n": "Eesti" }, + { "i": 429, "s": "eu", "n": "Euskara" }, + { "i": 21, "s": "fa", "n": "فارسی" }, + { "i": 22, "s": "fi", "n": "Suomi" }, + { "i": 473, "s": "fil", "n": "Filipino" }, + { "i": 23, "s": "fo", "n": "Føroyskt" }, + { "i": 478, "s": "fr-be", "n": "Français de Belgique" }, + { "i": 475, "s": "fr-ca", "n": "Français (Canada)" }, + { "i": 474, "s": "fr-ch", "n": "Français de Suisse" }, + { "i": 25, "s": "fur", "n": "Furlan" }, + { "i": 26, "s": "fy", "n": "Frysk" }, + { "i": 27, "s": "ga", "n": "Gaeilge" }, + { "i": 476, "s": "gd", "n": "Gàidhlig" }, + { "i": 457, "s": "gl", "n": "Galego" }, + { "i": 430, "s": "gn", "n": "Avañeẽ" }, + { "i": 28, "s": "gu", "n": "ગુજરાતી" }, + { "i": 30, "s": "hi", "n": "हिन्दी" }, + { "i": 431, "s": "hr", "n": "Hrvatski" }, + { "i": 31, "s": "hu", "n": "Magyar" }, + { "i": 467, "s": "hy", "n": "Armenian" }, + { "i": 32, "s": "ia", "n": "Interlingua" }, + { "i": 432, "s": "ii", "n": "ꆇꉙ" }, + { "i": 469, "s": "ilo", "n": "Ilokano" }, + { "i": 34, "s": "is", "n": "Íslenska" }, + { "i": 37, "s": "ka", "n": "ქართული" }, + { "i": 462, "s": "kk", "n": "Қазақ тілі" }, + { "i": 38, "s": "km", "n": "ភាសាខ្មែរ" }, + { "i": 39, "s": "kn", "n": "ಕನ್ನಡ" }, + { "i": 433, "s": "ks", "n": "कश्मीरी - (كشميري)" }, + { "i": 41, "s": "ku", "n": "Kurdî / كوردي" }, + { "i": 434, "s": "kv", "n": "Коми" }, + { "i": 479, "s": "ky", "n": "кыргыз тили" }, + { "i": 42, "s": "la", "n": "Latina" }, + { "i": 43, "s": "li", "n": "Limburgs" }, + { "i": 44, "s": "lo", "n": "ລາວ" }, + { "i": 45, "s": "lt", "n": "Lietuvių" }, + { "i": 453, "s": "lv", "n": "Latviešu valoda" }, + { "i": 435, "s": "mk", "n": "Македонски" }, + { "i": 46, "s": "ml", "n": "മലയാളം" }, + { "i": 472, "s": "mn", "n": "монгол хэл" }, + { "i": 461, "s": "mr", "n": "मराठी Marāṭhī" }, + { "i": 47, "s": "ms", "n": "Bahasa Melayu" }, + { "i": 465, "s": "mt", "n": "Malti" }, + { "i": 464, "s": "mwl", "n": "Mirandés" }, + { "i": 436, "s": "nah", "n": "Nahuatl" }, + { "i": 437, "s": "nap", "n": "Nnapulitano" }, + { "i": 48, "s": "nds", "n": "Plattdüütsch" }, + { "i": 456, "s": "ne", "n": "Nepali" }, + { "i": 50, "s": "nn", "n": "Norsk (nynorsk)" }, + { "i": 51, "s": "no", "n": "Norsk (bokmål)" }, + { "i": 52, "s": "non", "n": "Norrǿna" }, + { "i": 53, "s": "nv", "n": "Diné bizaad" }, + { "i": 54, "s": "oc", "n": "Occitan" }, + { "i": 55, "s": "or", "n": "ଓଡ଼ିଆ" }, + { "i": 56, "s": "os", "n": "Иронау" }, + { "i": 57, "s": "pa", "n": "ਪੰਜਾਬੀ" }, + { "i": 58, "s": "pl", "n": "Polski" }, + { "i": 59, "s": "ps", "n": "پښتو" }, + { "i": 60, "s": "pt", "n": "Português" }, + { "i": 439, "s": "qu", "n": "Runa Simi" }, + { "i": 61, "s": "ro", "n": "Română" }, + { "i": 483, "s": "rup", "n": "Armãneashce" }, + { "i": 63, "s": "sc", "n": "Sardu" }, + { "i": 440, "s": "sd", "n": "سنڌي" }, + { "i": 471, "s": "si", "n": "Sinhala" }, + { "i": 64, "s": "sk", "n": "Slovenčina" }, + { "i": 65, "s": "sl", "n": "Slovenščina" }, + { "i": 459, "s": "so", "n": "Somali" }, + { "i": 66, "s": "sq", "n": "Shqip" }, + { "i": 67, "s": "sr", "n": "Српски / Srpski" }, + { "i": 441, "s": "su", "n": "Basa Sunda" }, + { "i": 68, "s": "sv", "n": "Svenska" }, + { "i": 69, "s": "ta", "n": "தமிழ்" }, + { "i": 70, "s": "te", "n": "తెలుగు" }, + { "i": 71, "s": "th", "n": "ไทย" }, + { "i": 480, "s": "tir", "n": "Tigrigna" }, + { "i": 455, "s": "tl", "n": "Tagalog" }, + { "i": 72, "s": "tt", "n": "Tatarça" }, + { "i": 442, "s": "ty", "n": "Reo Mā`ohi" }, + { "i": 443, "s": "udm", "n": "Удмурт" }, + { "i": 444, "s": "ug", "n": "Uyghur"}, + { "i": 73, "s": "uk", "n": "Українська" }, + { "i": 74, "s": "ur", "n": "اردو" }, + { "i": 458, "s": "uz", "n": "Uzbek" }, + { "i": 463, "s": "va", "n": "valencià" }, + { "i": 445, "s": "vec", "n": "Vèneto" }, + { "i": 446, "s": "vi", "n": "Tiếng Việt" }, + { "i": 75, "s": "wa", "n": "Walon" }, + { "i": 447, "s": "xal", "n": "Хальмг" }, + { "i": 76, "s": "yi", "n": "ייִדיש" }, + { "i": 477, "s": "yo", "n": "èdè Yorùbá" }, + { "i": 448, "s": "za", "n": "Zhuang (Cuengh)" }, + { "i": 77, "s": "zh", "n": "中文" }, + { "i": 450, "s": "zh-hk", "n": "中文(繁體)" }, + { "i": 451, "s": "zh-sg", "n": "中文(简体)" } + ] +} +""" diff --git a/WordPressKit.xcodeproj/project.pbxproj b/WordPressKit.xcodeproj/project.pbxproj index 1e1b54ff..97b771d1 100644 --- a/WordPressKit.xcodeproj/project.pbxproj +++ b/WordPressKit.xcodeproj/project.pbxproj @@ -21,6 +21,25 @@ 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 */; }; 0C674E302BF3A91300F3B3D4 /* JetpackAIServiceRemote.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C674E2F2BF3A91300F3B3D4 /* JetpackAIServiceRemote.swift */; }; + 0C938A062C416789009BA7B2 /* Secret.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C938A052C416789009BA7B2 /* Secret.swift */; }; + 0C938A092C4167BC009BA7B2 /* NSString+XMLExtensions.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C938A072C4167BB009BA7B2 /* NSString+XMLExtensions.h */; }; + 0C938A0A2C4167BC009BA7B2 /* NSString+XMLExtensions.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C938A082C4167BB009BA7B2 /* NSString+XMLExtensions.m */; }; + 0C938A0C2C416850009BA7B2 /* String+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C938A0B2C416850009BA7B2 /* String+Helpers.swift */; }; + 0C938A112C4168FB009BA7B2 /* NSString+Helpers.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C938A0F2C416883009BA7B2 /* NSString+Helpers.h */; }; + 0C938A122C4168FB009BA7B2 /* NSString+Helpers.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C938A0D2C416876009BA7B2 /* NSString+Helpers.m */; }; + 0C938A142C416954009BA7B2 /* NSMutableData+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C938A132C416954009BA7B2 /* NSMutableData+Helpers.swift */; }; + 0C938A172C41698C009BA7B2 /* WPKitDateUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C938A152C41698C009BA7B2 /* WPKitDateUtils.h */; }; + 0C938A182C41698C009BA7B2 /* WPKitDateUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C938A162C41698C009BA7B2 /* WPKitDateUtils.m */; }; + 0C938A1A2C416A8E009BA7B2 /* WordPressComLanguageDatabase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C938A192C416A8E009BA7B2 /* WordPressComLanguageDatabase.swift */; }; + 0C938A1C2C416AE4009BA7B2 /* NSDate+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C938A1B2C416AE4009BA7B2 /* NSDate+Helpers.swift */; }; + 0C938A1E2C416AFC009BA7B2 /* Dictionary+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C938A1D2C416AFC009BA7B2 /* Dictionary+Helpers.swift */; }; + 0C938A212C416B41009BA7B2 /* NSBundle+VersionNumberHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C938A1F2C416B41009BA7B2 /* NSBundle+VersionNumberHelper.h */; }; + 0C938A222C416B41009BA7B2 /* NSBundle+VersionNumberHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C938A202C416B41009BA7B2 /* NSBundle+VersionNumberHelper.m */; }; + 0C938A252C416C35009BA7B2 /* WPMapFilterReduce.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C938A232C416C35009BA7B2 /* WPMapFilterReduce.m */; }; + 0C938A262C416C35009BA7B2 /* WPMapFilterReduce.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C938A242C416C35009BA7B2 /* WPMapFilterReduce.h */; }; + 0C938A282C416D0E009BA7B2 /* NSString+Summary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C938A272C416D0E009BA7B2 /* NSString+Summary.swift */; }; + 0C938A2B2C416DE0009BA7B2 /* DisplayableImageHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C938A292C416DE0009BA7B2 /* DisplayableImageHelper.m */; }; + 0C938A2C2C416DE0009BA7B2 /* DisplayableImageHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C938A2A2C416DE0009BA7B2 /* DisplayableImageHelper.h */; }; 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 */; }; @@ -777,6 +796,25 @@ 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 = ""; }; 0C674E2F2BF3A91300F3B3D4 /* JetpackAIServiceRemote.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JetpackAIServiceRemote.swift; sourceTree = ""; }; + 0C938A052C416789009BA7B2 /* Secret.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Secret.swift; sourceTree = ""; }; + 0C938A072C4167BB009BA7B2 /* NSString+XMLExtensions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+XMLExtensions.h"; sourceTree = ""; }; + 0C938A082C4167BB009BA7B2 /* NSString+XMLExtensions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+XMLExtensions.m"; sourceTree = ""; }; + 0C938A0B2C416850009BA7B2 /* String+Helpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+Helpers.swift"; sourceTree = ""; }; + 0C938A0D2C416876009BA7B2 /* NSString+Helpers.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSString+Helpers.m"; sourceTree = ""; }; + 0C938A0F2C416883009BA7B2 /* NSString+Helpers.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSString+Helpers.h"; sourceTree = ""; }; + 0C938A132C416954009BA7B2 /* NSMutableData+Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSMutableData+Helpers.swift"; sourceTree = ""; }; + 0C938A152C41698C009BA7B2 /* WPKitDateUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WPKitDateUtils.h; sourceTree = ""; }; + 0C938A162C41698C009BA7B2 /* WPKitDateUtils.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WPKitDateUtils.m; sourceTree = ""; }; + 0C938A192C416A8E009BA7B2 /* WordPressComLanguageDatabase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WordPressComLanguageDatabase.swift; sourceTree = ""; }; + 0C938A1B2C416AE4009BA7B2 /* NSDate+Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSDate+Helpers.swift"; sourceTree = ""; }; + 0C938A1D2C416AFC009BA7B2 /* Dictionary+Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Dictionary+Helpers.swift"; sourceTree = ""; }; + 0C938A1F2C416B41009BA7B2 /* NSBundle+VersionNumberHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSBundle+VersionNumberHelper.h"; sourceTree = ""; }; + 0C938A202C416B41009BA7B2 /* NSBundle+VersionNumberHelper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSBundle+VersionNumberHelper.m"; sourceTree = ""; }; + 0C938A232C416C35009BA7B2 /* WPMapFilterReduce.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WPMapFilterReduce.m; sourceTree = ""; }; + 0C938A242C416C35009BA7B2 /* WPMapFilterReduce.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WPMapFilterReduce.h; sourceTree = ""; }; + 0C938A272C416D0E009BA7B2 /* NSString+Summary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSString+Summary.swift"; sourceTree = ""; }; + 0C938A292C416DE0009BA7B2 /* DisplayableImageHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DisplayableImageHelper.m; sourceTree = ""; }; + 0C938A2A2C416DE0009BA7B2 /* DisplayableImageHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DisplayableImageHelper.h; 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 = ""; }; 0CB1905F2A2A6943004D3E80 /* blaze-campaigns-search.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "blaze-campaigns-search.json"; sourceTree = ""; }; @@ -1573,6 +1611,25 @@ 0C938A042C4166AC009BA7B2 /* WordPressShared */ = { isa = PBXGroup; children = ( + 0C938A052C416789009BA7B2 /* Secret.swift */, + 0C938A072C4167BB009BA7B2 /* NSString+XMLExtensions.h */, + 0C938A082C4167BB009BA7B2 /* NSString+XMLExtensions.m */, + 0C938A272C416D0E009BA7B2 /* NSString+Summary.swift */, + 0C938A2A2C416DE0009BA7B2 /* DisplayableImageHelper.h */, + 0C938A292C416DE0009BA7B2 /* DisplayableImageHelper.m */, + 0C938A0B2C416850009BA7B2 /* String+Helpers.swift */, + 0C938A0F2C416883009BA7B2 /* NSString+Helpers.h */, + 0C938A0D2C416876009BA7B2 /* NSString+Helpers.m */, + 0C938A132C416954009BA7B2 /* NSMutableData+Helpers.swift */, + 0C938A152C41698C009BA7B2 /* WPKitDateUtils.h */, + 0C938A162C41698C009BA7B2 /* WPKitDateUtils.m */, + 0C938A192C416A8E009BA7B2 /* WordPressComLanguageDatabase.swift */, + 0C938A1B2C416AE4009BA7B2 /* NSDate+Helpers.swift */, + 0C938A1D2C416AFC009BA7B2 /* Dictionary+Helpers.swift */, + 0C938A1F2C416B41009BA7B2 /* NSBundle+VersionNumberHelper.h */, + 0C938A202C416B41009BA7B2 /* NSBundle+VersionNumberHelper.m */, + 0C938A242C416C35009BA7B2 /* WPMapFilterReduce.h */, + 0C938A232C416C35009BA7B2 /* WPMapFilterReduce.m */, ); path = WordPressShared; sourceTree = ""; @@ -2098,6 +2155,7 @@ 3FE2E9762BC395C2002CA2E1 /* CoreAPI */, 3FE2E9532BB3F4ED002CA2E1 /* APIInterface */, 3FE2E9462BB12020002CA2E1 /* WordPressKit */, + 0C938A042C4166AC009BA7B2 /* WordPressShared */, ); path = Sources; sourceTree = ""; @@ -2129,7 +2187,6 @@ 3FE2E93F2BB11038002CA2E1 /* Models */, 3FE2E9402BB11075002CA2E1 /* Services */, 3FE2E9412BB110B3002CA2E1 /* Utility */, - 0C938A042C4166AC009BA7B2 /* WordPressShared */, 9368C77E1EC5EF1B0092CE8E /* WordPressKit.h */, 9368C77F1EC5EF1B0092CE8E /* Info.plist */, ); @@ -2737,10 +2794,12 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + 0C938A212C416B41009BA7B2 /* NSBundle+VersionNumberHelper.h in Headers */, 9368C78C1EC5EF1B0092CE8E /* WordPressKit.h in Headers */, 93C674F11EE8351E00BFAF05 /* NSMutableDictionary+Helpers.h in Headers */, 93BD273C1EE73282002BB00B /* AccountServiceRemoteREST.h in Headers */, 3FD635042BC3F05400CEDF5E /* WordPressComRESTAPIVersionedPathBuilder.h in Headers */, + 0C938A172C41698C009BA7B2 /* WPKitDateUtils.h in Headers */, 93BD27711EE737A8002BB00B /* ServiceRemoteWordPressXMLRPC.h in Headers */, 3FA4258F2BCCFDA6007539BF /* WordPressComRestApiErrorDomain.h in Headers */, 3FE2E9672BBEB8D2002CA2E1 /* WordPressComRESTAPIVersion.h in Headers */, @@ -2771,6 +2830,7 @@ 740B23B71F17EC7300067A2A /* PostServiceRemote.h in Headers */, C7971977267901D70072F984 /* SelfHostedPluginManagementClient.swift in Headers */, 740B23B81F17EC7300067A2A /* PostServiceRemoteREST.h in Headers */, + 0C938A092C4167BC009BA7B2 /* NSString+XMLExtensions.h in Headers */, C7971974267901D30072F984 /* JetpackPluginManagementClient.swift in Headers */, 74BA04F31F06DC0A00ED5CD8 /* CommentServiceRemoteREST.h in Headers */, C7971971267901D20072F984 /* PluginManagementClient.swift in Headers */, @@ -2778,6 +2838,7 @@ 9311A6851F22625A00704AC9 /* RemoteTaxonomyPaging.h in Headers */, 9311A68A1F22625A00704AC9 /* TaxonomyServiceRemoteXMLRPC.h in Headers */, 9311A6881F22625A00704AC9 /* TaxonomyServiceRemoteREST.h in Headers */, + 0C938A112C4168FB009BA7B2 /* NSString+Helpers.h in Headers */, 93188D1E1F2262BF0028ED4D /* RemotePostTag.h in Headers */, 9311A6871F22625A00704AC9 /* TaxonomyServiceRemote.h in Headers */, 9309994D1F1657C600F006A1 /* ThemeServiceRemote.h in Headers */, @@ -2785,8 +2846,10 @@ 740B23C41F17EE8000067A2A /* RemotePost.h in Headers */, 740B23C21F17EE8000067A2A /* RemotePostCategory.h in Headers */, B5A4822F20AC6C1A009D95F6 /* WPKitLogging.h in Headers */, + 0C938A262C416C35009BA7B2 /* WPMapFilterReduce.h in Headers */, 9309995B1F16616A00F006A1 /* RemoteTheme.h in Headers */, 1A4F98672279A87D00D86E8E /* WPKit-Swift.h in Headers */, + 0C938A2C2C416DE0009BA7B2 /* DisplayableImageHelper.h in Headers */, 93F50A371F226B9300B5BEBA /* WordPressComServiceRemote.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -3339,6 +3402,7 @@ 436D56332118D7AA00CEAA33 /* TransactionsServiceRemote.swift in Sources */, 93BD27721EE737A9002BB00B /* ServiceRemoteWordPressXMLRPC.m in Sources */, 4A05E79A2B2FDC3200C25E3B /* WordPressOrgRestApi.swift in Sources */, + 0C938A1E2C416AFC009BA7B2 /* Dictionary+Helpers.swift in Sources */, C76F456825B9F30E00BFEC87 /* JetpackScanHistory.swift in Sources */, E1D6B556200E46F300325669 /* WPTimeZone.swift in Sources */, 93F50A3F1F227C8900B5BEBA /* UsersServiceRemoteXMLRPC.swift in Sources */, @@ -3347,6 +3411,7 @@ 9F3E0B9E208733C3009CB5BA /* ReaderServiceDeliveryFrequency.swift in Sources */, 74E2295E1F1E777B0085F7F2 /* RemoteSharingButton.swift in Sources */, 4A05E7962B2FCB6400C25E3B /* NonceRetrieval.swift in Sources */, + 0C938A222C416B41009BA7B2 /* NSBundle+VersionNumberHelper.m in Sources */, 93BD27701EE737A8002BB00B /* ServiceRemoteWordPressComREST.m in Sources */, E61A51A621B172A900A5F902 /* RemoteWpcomPlan.swift in Sources */, 3FD634F62BC3AD6200CEDF5E /* AppTransportSecuritySettings.swift in Sources */, @@ -3369,6 +3434,7 @@ 9AB6D647218705E90008F274 /* RemoteDiff.swift in Sources */, 93BD277C1EE73944002BB00B /* HTTPAuthenticationAlertController.swift in Sources */, 7433BC011EFC4505002D9E92 /* PlanServiceRemote.swift in Sources */, + 0C938A062C416789009BA7B2 /* Secret.swift in Sources */, 4041405E220F9EF500CF7C5B /* StatsDotComFollowersInsight.swift in Sources */, 74650F721F0EA1A700188EDB /* GravatarServiceRemote.swift in Sources */, B5969E1D20A49AC4005E9DF1 /* NSString+MD5.m in Sources */, @@ -3387,6 +3453,7 @@ 4AE278442B2FAF6200E4D9B1 /* HTTPProtocolHelpers.swift in Sources */, FA68CD152993C6CD00FA4C29 /* BlazeServiceRemote.swift in Sources */, 4081976F221DDE9B00A298E4 /* StatsTopPostsTimeIntervalData.swift in Sources */, + 0C938A122C4168FB009BA7B2 /* NSString+Helpers.m in Sources */, 9311A68B1F22625A00704AC9 /* TaxonomyServiceRemoteXMLRPC.m in Sources */, C797196E2679007B0072F984 /* SelfHostedPluginManagementClient.swift in Sources */, 40414060220F9F1F00CF7C5B /* StatsAllTimesInsight.swift in Sources */, @@ -3398,12 +3465,14 @@ F4B0F4732ACAF498003ABC61 /* DomainsServiceRemote+AllDomains.swift in Sources */, E13EE1471F33258E00C15787 /* PluginServiceRemote.swift in Sources */, 93BD276A1EE736A8002BB00B /* RemoteUser.m in Sources */, + 0C938A1C2C416AE4009BA7B2 /* NSDate+Helpers.swift in Sources */, 742362D71F10250600BD0A7F /* MenusServiceRemote.m in Sources */, E6D0EE621F7EF9CE0064D3FC /* AccountServiceRemoteREST+SocialService.swift in Sources */, 8BB5F62127A99A2000B2FFAF /* DashboardServiceRemote.swift in Sources */, 74DA56351F06EAF000FE9BF4 /* MediaServiceRemoteXMLRPC.m in Sources */, C797196C2679007B0072F984 /* PluginManagementClient.swift in Sources */, C785325625B5F46C006CEAFB /* JetpackThreatFixStatus.swift in Sources */, + 0C938A252C416C35009BA7B2 /* WPMapFilterReduce.m in Sources */, 0CB190652A2A7569004D3E80 /* BlazeCampaignsSearchResponse.swift in Sources */, 93F50A381F226B9300B5BEBA /* WordPressComServiceRemote.m in Sources */, 0CED1FEB2B617D7D00E6DD52 /* AtomicLogs.swift in Sources */, @@ -3429,6 +3498,7 @@ 7328420421CD786C00126755 /* WordPressComServiceRemote+SiteCreation.swift in Sources */, 32FC1D28255C91ED00CD0A7B /* JetpackScan.swift in Sources */, FE5096612A2F852E00DDD071 /* RemotePublicizeInfo.swift in Sources */, + 0C938A0C2C416850009BA7B2 /* String+Helpers.swift in Sources */, 826016F31F9FA17B00533B6C /* Activity.swift in Sources */, 4A68E3D329406AA0004AC3DC /* RemoteMenu.swift in Sources */, 40819783221F5C8200A298E4 /* StatsPostDetails.swift in Sources */, @@ -3453,6 +3523,7 @@ 93C674F21EE8351E00BFAF05 /* NSMutableDictionary+Helpers.m in Sources */, 4624222D2548BA0F002B8A12 /* RemoteSiteDesign.swift in Sources */, 74D67F061F1528470010C5ED /* PeopleServiceRemote.swift in Sources */, + 0C938A2B2C416DE0009BA7B2 /* DisplayableImageHelper.m in Sources */, 98DC787522BAEBF200267279 /* StatsAllAnnualInsight.swift in Sources */, 740B23C31F17EE8000067A2A /* RemotePostCategory.m in Sources */, 8B2F4BF124ACE3C30056C08A /* RemoteReaderInterest.swift in Sources */, @@ -3475,6 +3546,7 @@ 404057CE221C38130060250C /* StatsTopVideosTimeIntervalData.swift in Sources */, 7E0D64FF22D855700092AD10 /* EditorServiceRemote.swift in Sources */, 0C1C08412B9CD79900E52F8C /* PostServiceRemoteExtended.swift in Sources */, + 0C938A1A2C416A8E009BA7B2 /* WordPressComLanguageDatabase.swift in Sources */, 9AF4F2FF2183346B00570E4B /* RemoteRevision.swift in Sources */, FE6C673A2BB739950083ECAB /* Decodable+Dictionary.swift in Sources */, 17D936252475D8AB008B2205 /* RemoteHomepageType.swift in Sources */, @@ -3484,6 +3556,7 @@ 0C1C08432B9CD8D200E52F8C /* PostServiceRemoteREST+Extended.swift in Sources */, 3FFCC0492BAB98130051D229 /* DateFormatter+WordPressCom.swift in Sources */, 74A44DD01F13C64B006CD8F4 /* RemoteNotification.swift in Sources */, + 0C938A182C41698C009BA7B2 /* WPKitDateUtils.m in Sources */, E1D6B558200E473A00325669 /* TimeZoneServiceRemote.swift in Sources */, 1769DEAA24729AFF00F42EFC /* HomepageSettingsServiceRemote.swift in Sources */, 93BD273D1EE73282002BB00B /* AccountServiceRemoteREST.m in Sources */, @@ -3494,6 +3567,7 @@ 3FE2E94F2BB29A1B002CA2E1 /* FilePart.m in Sources */, F41D98EA2B48602B004EC050 /* SessionDetails.swift in Sources */, 436D563C2118E18D00CEAA33 /* WPState.swift in Sources */, + 0C938A142C416954009BA7B2 /* NSMutableData+Helpers.swift in Sources */, 439A44DA2107C93000795ED7 /* RemotePlan_ApiVersion1_3.swift in Sources */, 93BD27811EE73944002BB00B /* WordPressOrgXMLRPCApi.swift in Sources */, 439A44D62107C66A00795ED7 /* JSONDecoderExtension.swift in Sources */, @@ -3509,6 +3583,8 @@ 74A44DCD1F13C533006CD8F4 /* PushAuthenticationServiceRemote.swift in Sources */, 0CB1905E2A2A5E83004D3E80 /* BlazeCampaign.swift in Sources */, 74B5F0D81EF8299B00B411E7 /* BlogServiceRemoteREST.m in Sources */, + 0C938A282C416D0E009BA7B2 /* NSString+Summary.swift in Sources */, + 0C938A0A2C4167BC009BA7B2 /* NSString+XMLExtensions.m in Sources */, 9FCDD09720A5EF75004F0BF7 /* ReaderTopicServiceError.swift in Sources */, 74A44DD11F13C64B006CD8F4 /* RemoteNotificationSettings.swift in Sources */, FEF7419D28085D89002C4203 /* RemoteBloggingPrompt.swift in Sources */, From d3af1d1e24a24a66b9ba3d7fb69e4a6c1e9986c3 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 12 Jul 2024 10:05:28 -0400 Subject: [PATCH 03/97] Update unit tests --- Sources/WordPressShared/Dictionary+Helpers.swift | 1 - .../WordPressShared/NSMutableData+Helpers.swift | 1 - .../WordPressComLanguageDatabase.swift | 2 -- .../Tests/RemoteReaderPostTests.m | 4 +++- WordPressKit.xcodeproj/project.pbxproj | 12 ++++++------ .../xcshareddata/swiftpm/Package.resolved | 15 +++++++++++++++ 6 files changed, 24 insertions(+), 11 deletions(-) create mode 100644 WordPressKit.xcworkspace/xcshareddata/swiftpm/Package.resolved diff --git a/Sources/WordPressShared/Dictionary+Helpers.swift b/Sources/WordPressShared/Dictionary+Helpers.swift index f981af95..76d50ad5 100644 --- a/Sources/WordPressShared/Dictionary+Helpers.swift +++ b/Sources/WordPressShared/Dictionary+Helpers.swift @@ -1,6 +1,5 @@ import Foundation - // MARK: - Dictionary Helper Methods // extension Dictionary { diff --git a/Sources/WordPressShared/NSMutableData+Helpers.swift b/Sources/WordPressShared/NSMutableData+Helpers.swift index 0983d7dd..6f5966ee 100644 --- a/Sources/WordPressShared/NSMutableData+Helpers.swift +++ b/Sources/WordPressShared/NSMutableData+Helpers.swift @@ -1,6 +1,5 @@ import Foundation - /// Encapsulates all of the NSMutableData Helper Methods. /// extension NSMutableData { diff --git a/Sources/WordPressShared/WordPressComLanguageDatabase.swift b/Sources/WordPressShared/WordPressComLanguageDatabase.swift index 7055fe67..21f8c4e8 100644 --- a/Sources/WordPressShared/WordPressComLanguageDatabase.swift +++ b/Sources/WordPressShared/WordPressComLanguageDatabase.swift @@ -17,7 +17,6 @@ class WordPressComLanguageDatabase: NSObject { /// let grouped: [[Language]] - // MARK: - Methods /// Designated Initializer: will load the languages contained within the `Languages.json` file. @@ -38,7 +37,6 @@ class WordPressComLanguageDatabase: NSObject { grouped = [popular] + [all] } - /// Returns the Human Readable name for a given Language Identifier /// /// - Parameter languageId: The Identifier of the language. diff --git a/Tests/WordPressKitTests/Tests/RemoteReaderPostTests.m b/Tests/WordPressKitTests/Tests/RemoteReaderPostTests.m index 78804a77..c5aedf61 100644 --- a/Tests/WordPressKitTests/Tests/RemoteReaderPostTests.m +++ b/Tests/WordPressKitTests/Tests/RemoteReaderPostTests.m @@ -5,6 +5,8 @@ #import "RemoteReaderPost.h" #import "WPKit-Swift.h" +@import WordPressKit; + @interface RemoteReaderPost () - (RemoteReaderPost *)formatPostDictionary:(NSDictionary *)dict; @@ -218,7 +220,7 @@ - (void)testSortDateFromDictionary { RemoteReaderPost *remoteReaderPost = [RemoteReaderPost alloc]; NSDate *now = [NSDate dateWithTimeIntervalSince1970:0]; - NSString *dateStr = [DateUtils isoStringFromDate:now]; + NSString *dateStr = [WPKitDateUtils isoStringFromDate:now]; NSMutableDictionary *dict = [NSMutableDictionary dictionary]; [dict setObject:dateStr forKey:@"date"]; diff --git a/WordPressKit.xcodeproj/project.pbxproj b/WordPressKit.xcodeproj/project.pbxproj index 97b771d1..87014790 100644 --- a/WordPressKit.xcodeproj/project.pbxproj +++ b/WordPressKit.xcodeproj/project.pbxproj @@ -22,24 +22,24 @@ 0C1C08452B9CDB0B00E52F8C /* PostServiceRemoteXMLRPC+Extended.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C1C08442B9CDB0B00E52F8C /* PostServiceRemoteXMLRPC+Extended.swift */; }; 0C674E302BF3A91300F3B3D4 /* JetpackAIServiceRemote.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C674E2F2BF3A91300F3B3D4 /* JetpackAIServiceRemote.swift */; }; 0C938A062C416789009BA7B2 /* Secret.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C938A052C416789009BA7B2 /* Secret.swift */; }; - 0C938A092C4167BC009BA7B2 /* NSString+XMLExtensions.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C938A072C4167BB009BA7B2 /* NSString+XMLExtensions.h */; }; + 0C938A092C4167BC009BA7B2 /* NSString+XMLExtensions.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C938A072C4167BB009BA7B2 /* NSString+XMLExtensions.h */; settings = {ATTRIBUTES = (Public, ); }; }; 0C938A0A2C4167BC009BA7B2 /* NSString+XMLExtensions.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C938A082C4167BB009BA7B2 /* NSString+XMLExtensions.m */; }; 0C938A0C2C416850009BA7B2 /* String+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C938A0B2C416850009BA7B2 /* String+Helpers.swift */; }; - 0C938A112C4168FB009BA7B2 /* NSString+Helpers.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C938A0F2C416883009BA7B2 /* NSString+Helpers.h */; }; + 0C938A112C4168FB009BA7B2 /* NSString+Helpers.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C938A0F2C416883009BA7B2 /* NSString+Helpers.h */; settings = {ATTRIBUTES = (Public, ); }; }; 0C938A122C4168FB009BA7B2 /* NSString+Helpers.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C938A0D2C416876009BA7B2 /* NSString+Helpers.m */; }; 0C938A142C416954009BA7B2 /* NSMutableData+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C938A132C416954009BA7B2 /* NSMutableData+Helpers.swift */; }; - 0C938A172C41698C009BA7B2 /* WPKitDateUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C938A152C41698C009BA7B2 /* WPKitDateUtils.h */; }; + 0C938A172C41698C009BA7B2 /* WPKitDateUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C938A152C41698C009BA7B2 /* WPKitDateUtils.h */; settings = {ATTRIBUTES = (Public, ); }; }; 0C938A182C41698C009BA7B2 /* WPKitDateUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C938A162C41698C009BA7B2 /* WPKitDateUtils.m */; }; 0C938A1A2C416A8E009BA7B2 /* WordPressComLanguageDatabase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C938A192C416A8E009BA7B2 /* WordPressComLanguageDatabase.swift */; }; 0C938A1C2C416AE4009BA7B2 /* NSDate+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C938A1B2C416AE4009BA7B2 /* NSDate+Helpers.swift */; }; 0C938A1E2C416AFC009BA7B2 /* Dictionary+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C938A1D2C416AFC009BA7B2 /* Dictionary+Helpers.swift */; }; - 0C938A212C416B41009BA7B2 /* NSBundle+VersionNumberHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C938A1F2C416B41009BA7B2 /* NSBundle+VersionNumberHelper.h */; }; + 0C938A212C416B41009BA7B2 /* NSBundle+VersionNumberHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C938A1F2C416B41009BA7B2 /* NSBundle+VersionNumberHelper.h */; settings = {ATTRIBUTES = (Public, ); }; }; 0C938A222C416B41009BA7B2 /* NSBundle+VersionNumberHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C938A202C416B41009BA7B2 /* NSBundle+VersionNumberHelper.m */; }; 0C938A252C416C35009BA7B2 /* WPMapFilterReduce.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C938A232C416C35009BA7B2 /* WPMapFilterReduce.m */; }; - 0C938A262C416C35009BA7B2 /* WPMapFilterReduce.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C938A242C416C35009BA7B2 /* WPMapFilterReduce.h */; }; + 0C938A262C416C35009BA7B2 /* WPMapFilterReduce.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C938A242C416C35009BA7B2 /* WPMapFilterReduce.h */; settings = {ATTRIBUTES = (Public, ); }; }; 0C938A282C416D0E009BA7B2 /* NSString+Summary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C938A272C416D0E009BA7B2 /* NSString+Summary.swift */; }; 0C938A2B2C416DE0009BA7B2 /* DisplayableImageHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C938A292C416DE0009BA7B2 /* DisplayableImageHelper.m */; }; - 0C938A2C2C416DE0009BA7B2 /* DisplayableImageHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C938A2A2C416DE0009BA7B2 /* DisplayableImageHelper.h */; }; + 0C938A2C2C416DE0009BA7B2 /* DisplayableImageHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C938A2A2C416DE0009BA7B2 /* DisplayableImageHelper.h */; settings = {ATTRIBUTES = (Public, ); }; }; 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 */; }; diff --git a/WordPressKit.xcworkspace/xcshareddata/swiftpm/Package.resolved b/WordPressKit.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 00000000..0cf274e7 --- /dev/null +++ b/WordPressKit.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,15 @@ +{ + "originHash" : "f28a54e288718485642adbe7b780a05abf05f95f0f435b3f87b6d3684b95d268", + "pins" : [ + { + "identity" : "test-collector-swift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/buildkite/test-collector-swift", + "state" : { + "revision" : "6e46839e1a4507ee047acd0896e29b9b278d9e3a", + "version" : "0.4.0" + } + } + ], + "version" : 3 +} From 4f7f0addef805b5f7f82e511cb3e857b26d1dba8 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 12 Jul 2024 10:08:14 -0400 Subject: [PATCH 04/97] Remove UIDeviceIdentifier dependency --- Podfile | 1 - Podfile.lock | 6 +----- .../Services/NotificationSettingsServiceRemote.swift | 3 +-- .../WordPressKit/Utility/UIDevice+Extensions.swift | 11 +++++++++++ WordPressKit.podspec | 5 ----- WordPressKit.xcodeproj/project.pbxproj | 6 ++++-- 6 files changed, 17 insertions(+), 15 deletions(-) create mode 100644 Sources/WordPressKit/Utility/UIDevice+Extensions.swift diff --git a/Podfile b/Podfile index 025097ca..3be7f32c 100644 --- a/Podfile +++ b/Podfile @@ -18,7 +18,6 @@ end def wordpresskit_pods pod 'NSObject-SafeExpectations', '~> 0.0.4' pod 'wpxmlrpc', '~> 0.10.0' - pod 'UIDeviceIdentifier', '~> 2.0' end ## WordPress Kit diff --git a/Podfile.lock b/Podfile.lock index 01a0933c..fe2c1614 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -18,7 +18,6 @@ PODS: - OHHTTPStubs/Swift (9.1.0): - OHHTTPStubs/Default - SwiftLint (0.54.0) - - UIDeviceIdentifier (2.3.0) - wpxmlrpc (0.10.0) DEPENDENCIES: @@ -28,7 +27,6 @@ DEPENDENCIES: - OHHTTPStubs (~> 9.0) - OHHTTPStubs/Swift (~> 9.0) - SwiftLint (= 0.54.0) - - UIDeviceIdentifier (~> 2.0) - wpxmlrpc (~> 0.10.0) SPEC REPOS: @@ -38,7 +36,6 @@ SPEC REPOS: - OCMock - OHHTTPStubs - SwiftLint - - UIDeviceIdentifier - wpxmlrpc SPEC CHECKSUMS: @@ -47,9 +44,8 @@ SPEC CHECKSUMS: OCMock: 300b1b1b9155cb6378660b981c2557448830bdc6 OHHTTPStubs: 90eac6d8f2c18317baeca36698523dc67c513831 SwiftLint: c1de071d9d08c8aba837545f6254315bc900e211 - UIDeviceIdentifier: 442b65b4ff1832d4ca9c2a157815cb29ad981b17 wpxmlrpc: 68db063041e85d186db21f674adf08d9c70627fd -PODFILE CHECKSUM: d7336a949e31a4e569b4a06da5c8eac29f5eca45 +PODFILE CHECKSUM: f25b3b5efc3fdad841c2948c5275472b97b1725e COCOAPODS: 1.15.2 diff --git a/Sources/WordPressKit/Services/NotificationSettingsServiceRemote.swift b/Sources/WordPressKit/Services/NotificationSettingsServiceRemote.swift index ca42d0bd..334bb71f 100644 --- a/Sources/WordPressKit/Services/NotificationSettingsServiceRemote.swift +++ b/Sources/WordPressKit/Services/NotificationSettingsServiceRemote.swift @@ -1,5 +1,4 @@ import Foundation -import UIDeviceIdentifier /// The purpose of this class is to encapsulate all of the interaction with the Notifications REST endpoints. /// Here we'll deal mostly with the Settings / Push Notifications API. @@ -76,7 +75,7 @@ open class NotificationSettingsServiceRemote: ServiceRemoteWordPressComREST { "device_family": "apple", "app_secret_key": pushNotificationAppId, "device_name": device.name, - "device_model": UIDeviceHardware.platform(), + "device_model": device.platform, "os_version": device.systemVersion, "app_version": Bundle.main.wpkit_bundleVersion(), "device_uuid": device.identifierForVendor?.uuidString diff --git a/Sources/WordPressKit/Utility/UIDevice+Extensions.swift b/Sources/WordPressKit/Utility/UIDevice+Extensions.swift new file mode 100644 index 00000000..808427df --- /dev/null +++ b/Sources/WordPressKit/Utility/UIDevice+Extensions.swift @@ -0,0 +1,11 @@ +import UIKit + +extension UIDevice { + var platform: String { + var size = 0 + sysctlbyname("hw.machine", nil, &size, nil, 0) + var machine = [CChar](repeating: 0, count: size) + sysctlbyname("hw.machine", &machine, &size, nil, 0) + return String(cString: machine) + } +} diff --git a/WordPressKit.podspec b/WordPressKit.podspec index 85eefdbe..1375a772 100644 --- a/WordPressKit.podspec +++ b/WordPressKit.podspec @@ -25,9 +25,4 @@ Pod::Spec.new do |s| s.dependency 'NSObject-SafeExpectations', '~> 0.0.4' s.dependency 'wpxmlrpc', '~> 0.10' - s.dependency 'UIDeviceIdentifier', '~> 2.0' - - # Use a loose restriction that allows both production and beta versions, up to the next major version. - # If you want to update which of these is used, specify it in the host app. - s.dependency 'WordPressShared', '~> 2.0-beta' end diff --git a/WordPressKit.xcodeproj/project.pbxproj b/WordPressKit.xcodeproj/project.pbxproj index 87014790..2fbdefe2 100644 --- a/WordPressKit.xcodeproj/project.pbxproj +++ b/WordPressKit.xcodeproj/project.pbxproj @@ -44,6 +44,7 @@ 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 */; }; 0CB190652A2A7569004D3E80 /* BlazeCampaignsSearchResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CB190642A2A7569004D3E80 /* BlazeCampaignsSearchResponse.swift */; }; + 0CCD4C5C2C41700B00B53F9A /* UIDevice+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CCD4C5B2C41700B00B53F9A /* UIDevice+Extensions.swift */; }; 0CED1FE82B617CF300E6DD52 /* AtomicSiteServiceRemote.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CED1FE72B617CF300E6DD52 /* AtomicSiteServiceRemote.swift */; }; 0CED1FEB2B617D7D00E6DD52 /* AtomicLogs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CED1FEA2B617D7D00E6DD52 /* AtomicLogs.swift */; }; 1769DEAA24729AFF00F42EFC /* HomepageSettingsServiceRemote.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1769DEA924729AFF00F42EFC /* HomepageSettingsServiceRemote.swift */; }; @@ -819,6 +820,7 @@ 0CB1905D2A2A5E83004D3E80 /* BlazeCampaign.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlazeCampaign.swift; sourceTree = ""; }; 0CB1905F2A2A6943004D3E80 /* blaze-campaigns-search.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "blaze-campaigns-search.json"; sourceTree = ""; }; 0CB190642A2A7569004D3E80 /* BlazeCampaignsSearchResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlazeCampaignsSearchResponse.swift; sourceTree = ""; }; + 0CCD4C5B2C41700B00B53F9A /* UIDevice+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIDevice+Extensions.swift"; sourceTree = ""; }; 0CED1FE72B617CF300E6DD52 /* AtomicSiteServiceRemote.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AtomicSiteServiceRemote.swift; sourceTree = ""; }; 0CED1FEA2B617D7D00E6DD52 /* AtomicLogs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AtomicLogs.swift; sourceTree = ""; }; 1769DEA924729AFF00F42EFC /* HomepageSettingsServiceRemote.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomepageSettingsServiceRemote.swift; sourceTree = ""; }; @@ -2037,6 +2039,7 @@ 465F88A1263B325C00F4C950 /* ChecksumUtil.swift */, 3F3195AC266FF94B00397EE7 /* ZendeskMetadata.swift */, 4AE278432B2FAF6200E4D9B1 /* HTTPProtocolHelpers.swift */, + 0CCD4C5B2C41700B00B53F9A /* UIDevice+Extensions.swift */, ); path = Utility; sourceTree = ""; @@ -3344,7 +3347,6 @@ inputPaths = ( "${PODS_ROOT}/Target Support Files/Pods-WordPressKitTests/Pods-WordPressKitTests-frameworks.sh", "${BUILT_PRODUCTS_DIR}/NSObject-SafeExpectations/NSObject_SafeExpectations.framework", - "${BUILT_PRODUCTS_DIR}/UIDeviceIdentifier/UIDeviceIdentifier.framework", "${BUILT_PRODUCTS_DIR}/wpxmlrpc/wpxmlrpc.framework", "${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework", "${BUILT_PRODUCTS_DIR}/OCMock/OCMock.framework", @@ -3353,7 +3355,6 @@ name = "[CP] Embed Pods Frameworks"; outputPaths = ( "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/NSObject_SafeExpectations.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/UIDeviceIdentifier.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/wpxmlrpc.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Alamofire.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OCMock.framework", @@ -3586,6 +3587,7 @@ 0C938A282C416D0E009BA7B2 /* NSString+Summary.swift in Sources */, 0C938A0A2C4167BC009BA7B2 /* NSString+XMLExtensions.m in Sources */, 9FCDD09720A5EF75004F0BF7 /* ReaderTopicServiceError.swift in Sources */, + 0CCD4C5C2C41700B00B53F9A /* UIDevice+Extensions.swift in Sources */, 74A44DD11F13C64B006CD8F4 /* RemoteNotificationSettings.swift in Sources */, FEF7419D28085D89002C4203 /* RemoteBloggingPrompt.swift in Sources */, 74DA56331F06EAF000FE9BF4 /* MediaServiceRemoteREST.m in Sources */, From ee95d78682c86463393297e31a39c437586b811e Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 12 Jul 2024 10:13:02 -0400 Subject: [PATCH 05/97] Link NSObject-SafeExpectations and wpxmlrpc statically --- Podfile | 11 --- Podfile.lock | 10 +-- WordPressKit.xcodeproj/project.pbxproj | 75 +++++++++---------- .../xcshareddata/swiftpm/Package.resolved | 20 ++++- 4 files changed, 56 insertions(+), 60 deletions(-) diff --git a/Podfile b/Podfile index 3be7f32c..92dd7581 100644 --- a/Podfile +++ b/Podfile @@ -15,22 +15,11 @@ def swiftlint_version YAML.load_file('.swiftlint.yml')['swiftlint_version'] end -def wordpresskit_pods - pod 'NSObject-SafeExpectations', '~> 0.0.4' - pod 'wpxmlrpc', '~> 0.10.0' -end - ## WordPress Kit ## ============= -## -target 'WordPressKit' do - project 'WordPressKit.xcodeproj' - wordpresskit_pods -end target 'WordPressKitTests' do project 'WordPressKit.xcodeproj' - wordpresskit_pods pod 'OHHTTPStubs', '~> 9.0' pod 'OHHTTPStubs/Swift', '~> 9.0' diff --git a/Podfile.lock b/Podfile.lock index fe2c1614..cdcd076f 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -1,6 +1,5 @@ PODS: - Alamofire (5.8.1) - - NSObject-SafeExpectations (0.0.6) - OCMock (3.9.3) - OHHTTPStubs (9.1.0): - OHHTTPStubs/Default (= 9.1.0) @@ -18,34 +17,27 @@ PODS: - OHHTTPStubs/Swift (9.1.0): - OHHTTPStubs/Default - SwiftLint (0.54.0) - - wpxmlrpc (0.10.0) DEPENDENCIES: - Alamofire (~> 5.0) - - NSObject-SafeExpectations (~> 0.0.4) - OCMock (~> 3.4) - OHHTTPStubs (~> 9.0) - OHHTTPStubs/Swift (~> 9.0) - SwiftLint (= 0.54.0) - - wpxmlrpc (~> 0.10.0) SPEC REPOS: trunk: - Alamofire - - NSObject-SafeExpectations - OCMock - OHHTTPStubs - SwiftLint - - wpxmlrpc SPEC CHECKSUMS: Alamofire: 3ca42e259043ee0dc5c0cdd76c4bc568b8e42af7 - NSObject-SafeExpectations: c01c8881cbd97efad6f668286b913cd0b7d62ab5 OCMock: 300b1b1b9155cb6378660b981c2557448830bdc6 OHHTTPStubs: 90eac6d8f2c18317baeca36698523dc67c513831 SwiftLint: c1de071d9d08c8aba837545f6254315bc900e211 - wpxmlrpc: 68db063041e85d186db21f674adf08d9c70627fd -PODFILE CHECKSUM: f25b3b5efc3fdad841c2948c5275472b97b1725e +PODFILE CHECKSUM: f2a6a7320f647a36041a34f152598d1549c4a7e1 COCOAPODS: 1.15.2 diff --git a/WordPressKit.xcodeproj/project.pbxproj b/WordPressKit.xcodeproj/project.pbxproj index 2fbdefe2..58dac7df 100644 --- a/WordPressKit.xcodeproj/project.pbxproj +++ b/WordPressKit.xcodeproj/project.pbxproj @@ -45,6 +45,8 @@ 0CB190612A2A6A13004D3E80 /* blaze-campaigns-search.json in Resources */ = {isa = PBXBuildFile; fileRef = 0CB1905F2A2A6943004D3E80 /* blaze-campaigns-search.json */; }; 0CB190652A2A7569004D3E80 /* BlazeCampaignsSearchResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CB190642A2A7569004D3E80 /* BlazeCampaignsSearchResponse.swift */; }; 0CCD4C5C2C41700B00B53F9A /* UIDevice+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CCD4C5B2C41700B00B53F9A /* UIDevice+Extensions.swift */; }; + 0CCD4C5F2C41711800B53F9A /* NSObject-SafeExpectations in Frameworks */ = {isa = PBXBuildFile; productRef = 0CCD4C5E2C41711800B53F9A /* NSObject-SafeExpectations */; }; + 0CCD4C622C41712800B53F9A /* wpxmlrpc in Frameworks */ = {isa = PBXBuildFile; productRef = 0CCD4C612C41712800B53F9A /* wpxmlrpc */; }; 0CED1FE82B617CF300E6DD52 /* AtomicSiteServiceRemote.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CED1FE72B617CF300E6DD52 /* AtomicSiteServiceRemote.swift */; }; 0CED1FEB2B617D7D00E6DD52 /* AtomicLogs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CED1FEA2B617D7D00E6DD52 /* AtomicLogs.swift */; }; 1769DEAA24729AFF00F42EFC /* HomepageSettingsServiceRemote.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1769DEA924729AFF00F42EFC /* HomepageSettingsServiceRemote.swift */; }; @@ -579,7 +581,6 @@ 9F3E0BAE20873836009CB5BA /* ReaderTopicServiceRemoteTest+Subscriptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F3E0BAD20873835009CB5BA /* ReaderTopicServiceRemoteTest+Subscriptions.swift */; }; 9F4E52002088E38200424676 /* ObjectValidation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F4E51FF2088E38200424676 /* ObjectValidation.swift */; }; 9FCDD09720A5EF75004F0BF7 /* ReaderTopicServiceError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FCDD09620A5EF75004F0BF7 /* ReaderTopicServiceError.swift */; }; - A0EEB8CB04BEA5F9083EBACE /* Pods_WordPressKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EFF80A6E6EE37118CB1DA158 /* Pods_WordPressKit.framework */; }; AB49D09325D1A85D0084905B /* PostServiceRemoteRESTLikesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AB49D09225D1A85D0084905B /* PostServiceRemoteRESTLikesTests.swift */; }; AB49D09725D1AC0A0084905B /* post-likes-success.json in Resources */ = {isa = PBXBuildFile; fileRef = AB49D09625D1AC0A0084905B /* post-likes-success.json */; }; AB49D0B325D1B4D80084905B /* post-likes-failure.json in Resources */ = {isa = PBXBuildFile; fileRef = AB49D0B225D1B4D80084905B /* post-likes-failure.json */; }; @@ -1009,7 +1010,6 @@ 4AE278492B2FC6C600E4D9B1 /* HTTPHeaderValueParserTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HTTPHeaderValueParserTests.swift; sourceTree = ""; }; 4AE7E36A2B9A995500C8CED5 /* AnnouncementServiceRemoteTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnnouncementServiceRemoteTests.swift; sourceTree = ""; }; 4AE7E36C2B9A9BC400C8CED5 /* site-zendesk-metadata-success.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "site-zendesk-metadata-success.json"; sourceTree = ""; }; - 6C2A33D76FD1052D6F30466D /* Pods-WordPressKit.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WordPressKit.debug.xcconfig"; path = "Pods/Target Support Files/Pods-WordPressKit/Pods-WordPressKit.debug.xcconfig"; sourceTree = ""; }; 6F2E0CC4FA01B5475A378DA2 /* Pods-WordPressKitTests.release-alpha.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WordPressKitTests.release-alpha.xcconfig"; path = "Pods/Target Support Files/Pods-WordPressKitTests/Pods-WordPressKitTests.release-alpha.xcconfig"; sourceTree = ""; }; 730E869E21E44EFD00753E1A /* WordPressComServiceRemote+SiteVerticals.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WordPressComServiceRemote+SiteVerticals.swift"; sourceTree = ""; }; 731BA83521DECD61000FDFCD /* SiteCreationRequestEncodingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SiteCreationRequestEncodingTests.swift; sourceTree = ""; }; @@ -1405,7 +1405,6 @@ BA9A7F7E24C6895600925E81 /* plugin-directory-jetpack-beta.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "plugin-directory-jetpack-beta.json"; sourceTree = ""; }; BAB0E36324AD599700B3D22C /* MockPluginStateProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockPluginStateProvider.swift; sourceTree = ""; }; BAFA775524ADAB3C000F0D3A /* MockPluginDirectoryEntryProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockPluginDirectoryEntryProvider.swift; sourceTree = ""; }; - BEEC8B5D92DA614468900BD7 /* Pods-WordPressKit.release-alpha.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WordPressKit.release-alpha.xcconfig"; path = "Pods/Target Support Files/Pods-WordPressKit/Pods-WordPressKit.release-alpha.xcconfig"; sourceTree = ""; }; C5953994B3865AF409BA4210 /* Pods-WordPressKitTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WordPressKitTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-WordPressKitTests/Pods-WordPressKitTests.release.xcconfig"; sourceTree = ""; }; C738CAEE28622325001BE107 /* QRLoginServiceRemoteTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRLoginServiceRemoteTests.swift; sourceTree = ""; }; C738CAF0286224ED001BE107 /* qrlogin-validate-200.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "qrlogin-validate-200.json"; sourceTree = ""; }; @@ -1424,7 +1423,6 @@ C92EFF6C25E741E900E0308D /* common-starter-site-designs-malformed.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "common-starter-site-designs-malformed.json"; sourceTree = ""; }; C92EFF7225E7444400E0308D /* common-starter-site-designs-empty-designs.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "common-starter-site-designs-empty-designs.json"; sourceTree = ""; }; C9F991B827D5A52600135131 /* domain-service-invalid-query.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "domain-service-invalid-query.json"; sourceTree = ""; }; - CA5ABD95F40077D001644BCC /* Pods-WordPressKit.release-internal.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WordPressKit.release-internal.xcconfig"; path = "Pods/Target Support Files/Pods-WordPressKit/Pods-WordPressKit.release-internal.xcconfig"; sourceTree = ""; }; CEAD827925E421DE00758DF2 /* reader-post-comments-subscribe-failure.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "reader-post-comments-subscribe-failure.json"; sourceTree = ""; }; D813437521F6D70D0060D99A /* SiteSegmentsResponseDecodingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SiteSegmentsResponseDecodingTests.swift; sourceTree = ""; }; D813437721F6D7DC0060D99A /* site-segments-single.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "site-segments-single.json"; sourceTree = ""; }; @@ -1447,7 +1445,6 @@ E1E89C671FD6B2E9006E7A33 /* plugin-directory-jetpack.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "plugin-directory-jetpack.json"; sourceTree = ""; }; E1E89C691FD6BDB1006E7A33 /* PluginDirectoryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PluginDirectoryTests.swift; sourceTree = ""; }; E1EF5D5C1F9F329900B6D53E /* SitePluginCapabilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SitePluginCapabilities.swift; sourceTree = ""; }; - E33F1EA3284E0454909D1967 /* Pods-WordPressKit.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WordPressKit.release.xcconfig"; path = "Pods/Target Support Files/Pods-WordPressKit/Pods-WordPressKit.release.xcconfig"; sourceTree = ""; }; E61A51A521B172A900A5F902 /* RemoteWpcomPlan.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteWpcomPlan.swift; sourceTree = ""; }; E670CD712277A85000E75735 /* plans-me-sites-success.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "plans-me-sites-success.json"; sourceTree = ""; }; E689431D21B0A1A800C5E4A7 /* plans-mobile-success.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "plans-mobile-success.json"; sourceTree = ""; }; @@ -1460,7 +1457,6 @@ E6C1E8481EF21FC100D139D9 /* is-passwordless-account-success.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "is-passwordless-account-success.json"; sourceTree = ""; }; E6D0EE611F7EF9CE0064D3FC /* AccountServiceRemoteREST+SocialService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AccountServiceRemoteREST+SocialService.swift"; sourceTree = ""; }; ED05C8FF3E61D93CE5BA527E /* Pods_WordPressKitTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_WordPressKitTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - EFF80A6E6EE37118CB1DA158 /* Pods_WordPressKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_WordPressKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; F181EA0127184D3C00F26141 /* ProductServiceRemote.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProductServiceRemote.swift; sourceTree = ""; }; F194E1222417ED9F00874408 /* AtomicAuthenticationServiceRemoteTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AtomicAuthenticationServiceRemoteTests.swift; sourceTree = ""; }; F194E1242417EE7E00874408 /* atomic-get-auth-cookie-success.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "atomic-get-auth-cookie-success.json"; sourceTree = ""; }; @@ -1562,7 +1558,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - A0EEB8CB04BEA5F9083EBACE /* Pods_WordPressKit.framework in Frameworks */, + 0CCD4C5F2C41711800B53F9A /* NSObject-SafeExpectations in Frameworks */, + 0CCD4C622C41712800B53F9A /* wpxmlrpc in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1659,7 +1656,6 @@ 38C6ABE94A27A12C9C4AD19D /* Frameworks */ = { isa = PBXGroup; children = ( - EFF80A6E6EE37118CB1DA158 /* Pods_WordPressKit.framework */, ED05C8FF3E61D93CE5BA527E /* Pods_WordPressKitTests.framework */, ); name = Frameworks; @@ -2685,10 +2681,6 @@ E5EA953F7DD505CCED2E44CD /* Pods */ = { isa = PBXGroup; children = ( - 6C2A33D76FD1052D6F30466D /* Pods-WordPressKit.debug.xcconfig */, - E33F1EA3284E0454909D1967 /* Pods-WordPressKit.release.xcconfig */, - BEEC8B5D92DA614468900BD7 /* Pods-WordPressKit.release-alpha.xcconfig */, - CA5ABD95F40077D001644BCC /* Pods-WordPressKit.release-internal.xcconfig */, 264F5C834541BBF2018F4964 /* Pods-WordPressKitTests.debug.xcconfig */, C5953994B3865AF409BA4210 /* Pods-WordPressKitTests.release.xcconfig */, 6F2E0CC4FA01B5475A378DA2 /* Pods-WordPressKitTests.release-alpha.xcconfig */, @@ -2864,7 +2856,6 @@ isa = PBXNativeTarget; buildConfigurationList = 9368C78F1EC5EF1B0092CE8E /* Build configuration list for PBXNativeTarget "WordPressKit" */; buildPhases = ( - 50C31E8D1B97D5FA0D543935 /* [CP] Check Pods Manifest.lock */, 9368C7781EC5EF1B0092CE8E /* Headers */, 9368C7761EC5EF1B0092CE8E /* Sources */, 9368C7771EC5EF1B0092CE8E /* Frameworks */, @@ -2876,6 +2867,10 @@ dependencies = ( ); name = WordPressKit; + packageProductDependencies = ( + 0CCD4C5E2C41711800B53F9A /* NSObject-SafeExpectations */, + 0CCD4C612C41712800B53F9A /* wpxmlrpc */, + ); productName = WordPressKit; productReference = 9368C77B1EC5EF1B0092CE8E /* WordPressKit.framework */; productType = "com.apple.product-type.framework"; @@ -2936,6 +2931,8 @@ mainGroup = 9368C7711EC5EF1B0092CE8E; packageReferences = ( 3FB8642A2888089F003A86BE /* XCRemoteSwiftPackageReference "test-collector-swift" */, + 0CCD4C5D2C41711800B53F9A /* XCRemoteSwiftPackageReference "NSObject-SafeExpectations" */, + 0CCD4C602C41712800B53F9A /* XCRemoteSwiftPackageReference "wpxmlrpc" */, ); productRefGroup = 9368C77C1EC5EF1B0092CE8E /* Products */; projectDirPath = ""; @@ -3321,24 +3318,6 @@ shellPath = /bin/sh; shellScript = "./Pods/SwiftLint/swiftlint lint\n"; }; - 50C31E8D1B97D5FA0D543935 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-WordPressKit-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; B07A9DD36A28DB40846D1682 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -3346,16 +3325,12 @@ ); inputPaths = ( "${PODS_ROOT}/Target Support Files/Pods-WordPressKitTests/Pods-WordPressKitTests-frameworks.sh", - "${BUILT_PRODUCTS_DIR}/NSObject-SafeExpectations/NSObject_SafeExpectations.framework", - "${BUILT_PRODUCTS_DIR}/wpxmlrpc/wpxmlrpc.framework", "${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework", "${BUILT_PRODUCTS_DIR}/OCMock/OCMock.framework", "${BUILT_PRODUCTS_DIR}/OHHTTPStubs/OHHTTPStubs.framework", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/NSObject_SafeExpectations.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/wpxmlrpc.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Alamofire.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OCMock.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OHHTTPStubs.framework", @@ -3901,7 +3876,6 @@ }; 9368C7901EC5EF1B0092CE8E /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 6C2A33D76FD1052D6F30466D /* Pods-WordPressKit.debug.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "${inherited}"; APPLICATION_EXTENSION_API_ONLY = NO; @@ -3934,7 +3908,6 @@ }; 9368C7911EC5EF1B0092CE8E /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = E33F1EA3284E0454909D1967 /* Pods-WordPressKit.release.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "${inherited}"; APPLICATION_EXTENSION_API_ONLY = NO; @@ -4075,7 +4048,6 @@ }; 93D436181EC638A100626832 /* Release-Internal */ = { isa = XCBuildConfiguration; - baseConfigurationReference = CA5ABD95F40077D001644BCC /* Pods-WordPressKit.release-internal.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "${inherited}"; APPLICATION_EXTENSION_API_ONLY = NO; @@ -4191,7 +4163,6 @@ }; 93D4361B1EC638A800626832 /* Release-Alpha */ = { isa = XCBuildConfiguration; - baseConfigurationReference = BEEC8B5D92DA614468900BD7 /* Pods-WordPressKit.release-alpha.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "${inherited}"; APPLICATION_EXTENSION_API_ONLY = NO; @@ -4284,6 +4255,22 @@ /* End XCConfigurationList section */ /* Begin XCRemoteSwiftPackageReference section */ + 0CCD4C5D2C41711800B53F9A /* XCRemoteSwiftPackageReference "NSObject-SafeExpectations" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/wordpress-mobile/NSObject-SafeExpectations"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 0.0.6; + }; + }; + 0CCD4C602C41712800B53F9A /* XCRemoteSwiftPackageReference "wpxmlrpc" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/wordpress-mobile/wpxmlrpc"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 0.10.0; + }; + }; 3FB8642A2888089F003A86BE /* XCRemoteSwiftPackageReference "test-collector-swift" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/buildkite/test-collector-swift"; @@ -4295,6 +4282,16 @@ /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ + 0CCD4C5E2C41711800B53F9A /* NSObject-SafeExpectations */ = { + isa = XCSwiftPackageProductDependency; + package = 0CCD4C5D2C41711800B53F9A /* XCRemoteSwiftPackageReference "NSObject-SafeExpectations" */; + productName = "NSObject-SafeExpectations"; + }; + 0CCD4C612C41712800B53F9A /* wpxmlrpc */ = { + isa = XCSwiftPackageProductDependency; + package = 0CCD4C602C41712800B53F9A /* XCRemoteSwiftPackageReference "wpxmlrpc" */; + productName = wpxmlrpc; + }; 3FB8642B2888089F003A86BE /* BuildkiteTestCollector */ = { isa = XCSwiftPackageProductDependency; package = 3FB8642A2888089F003A86BE /* XCRemoteSwiftPackageReference "test-collector-swift" */; diff --git a/WordPressKit.xcworkspace/xcshareddata/swiftpm/Package.resolved b/WordPressKit.xcworkspace/xcshareddata/swiftpm/Package.resolved index 0cf274e7..a0da8255 100644 --- a/WordPressKit.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/WordPressKit.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,6 +1,15 @@ { - "originHash" : "f28a54e288718485642adbe7b780a05abf05f95f0f435b3f87b6d3684b95d268", + "originHash" : "eb780b1913f4e443c08925a87813106f18fbb44ec81075f26b522033a6416964", "pins" : [ + { + "identity" : "nsobject-safeexpectations", + "kind" : "remoteSourceControl", + "location" : "https://github.com/wordpress-mobile/NSObject-SafeExpectations", + "state" : { + "revision" : "eb84d994ab13a153888a19e5b99f536aafa77434", + "version" : "0.0.6" + } + }, { "identity" : "test-collector-swift", "kind" : "remoteSourceControl", @@ -9,6 +18,15 @@ "revision" : "6e46839e1a4507ee047acd0896e29b9b278d9e3a", "version" : "0.4.0" } + }, + { + "identity" : "wpxmlrpc", + "kind" : "remoteSourceControl", + "location" : "https://github.com/wordpress-mobile/wpxmlrpc", + "state" : { + "revision" : "bfc413d336bdeaab89e62dc483380baa99b2257e", + "version" : "0.10.0" + } } ], "version" : 3 From 721f854bc53fadc1a1793df562ad0b6d4c9099be Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 12 Jul 2024 10:14:29 -0400 Subject: [PATCH 06/97] Add a script to build xcframework --- create-xcframeworks.sh | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100755 create-xcframeworks.sh diff --git a/create-xcframeworks.sh b/create-xcframeworks.sh new file mode 100755 index 00000000..27651d7f --- /dev/null +++ b/create-xcframeworks.sh @@ -0,0 +1,27 @@ +ROOT="./.build/xcframeworks" + +rm -rf $ROOT + +for SDK in iphoneos iphonesimulator +do +xcodebuild archive \ + -workspace WordPressKit.xcworkspace \ + -scheme WordPressKit \ + -archivePath "$ROOT/WordPressKit-$SDK.xcarchive" \ + -sdk $SDK \ + SKIP_INSTALL=NO \ + BUILD_LIBRARY_FOR_DISTRIBUTION=YES \ + DEBUG_INFORMATION_FORMAT=DWARF +done + +xcodebuild -create-xcframework \ + -framework "$ROOT/WordPressKit-iphoneos.xcarchive/Products/Library/Frameworks/WordPressKit.framework" \ + -framework "$ROOT/WordPressKit-iphonesimulator.xcarchive/Products/Library/Frameworks/WordPressKit.framework" \ + -output "$ROOT/WordPressKit.xcframework" + +cd $ROOT +zip -r -X WordPressKit.zip *.xcframework +rm -rf *.xcframework + +swift package compute-checksum WordPressKit.zip +cd - From a883ef24b868592842bdfdc6130788d1a8f504cc Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 12 Jul 2024 10:27:35 -0400 Subject: [PATCH 07/97] (Test) import dependencies using @_implementationOnly --- Sources/CoreAPI/HTTPRequestBuilder.swift | 2 +- Sources/CoreAPI/WordPressOrgXMLRPCApi.swift | 2 +- Sources/WordPressKit/Models/RemoteBlog.swift | 2 +- Sources/WordPressKit/Models/RemoteReaderSiteInfo.swift | 2 +- .../Services/PostServiceRemoteXMLRPC+Extended.swift | 2 +- Sources/WordPressKit/Services/SharingServiceRemote.swift | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Sources/CoreAPI/HTTPRequestBuilder.swift b/Sources/CoreAPI/HTTPRequestBuilder.swift index 1cf8170b..506b8010 100644 --- a/Sources/CoreAPI/HTTPRequestBuilder.swift +++ b/Sources/CoreAPI/HTTPRequestBuilder.swift @@ -1,5 +1,5 @@ import Foundation -import wpxmlrpc +@_implementationOnly import wpxmlrpc /// A builder type that appends HTTP request data to a URL. /// diff --git a/Sources/CoreAPI/WordPressOrgXMLRPCApi.swift b/Sources/CoreAPI/WordPressOrgXMLRPCApi.swift index 2698c89f..58c57633 100644 --- a/Sources/CoreAPI/WordPressOrgXMLRPCApi.swift +++ b/Sources/CoreAPI/WordPressOrgXMLRPCApi.swift @@ -1,5 +1,5 @@ import Foundation -import wpxmlrpc +@_implementationOnly import wpxmlrpc /// Class to connect to the XMLRPC API on self hosted sites. open class WordPressOrgXMLRPCApi: NSObject { diff --git a/Sources/WordPressKit/Models/RemoteBlog.swift b/Sources/WordPressKit/Models/RemoteBlog.swift index 3351e059..99bea7dc 100644 --- a/Sources/WordPressKit/Models/RemoteBlog.swift +++ b/Sources/WordPressKit/Models/RemoteBlog.swift @@ -1,5 +1,5 @@ import Foundation -import NSObject_SafeExpectations +@_implementationOnly import NSObject_SafeExpectations /// This class encapsulates all of the *remote* Blog properties @objcMembers public class RemoteBlog: NSObject { diff --git a/Sources/WordPressKit/Models/RemoteReaderSiteInfo.swift b/Sources/WordPressKit/Models/RemoteReaderSiteInfo.swift index cde80240..01807e4b 100644 --- a/Sources/WordPressKit/Models/RemoteReaderSiteInfo.swift +++ b/Sources/WordPressKit/Models/RemoteReaderSiteInfo.swift @@ -1,5 +1,5 @@ import Foundation -import NSObject_SafeExpectations +@_implementationOnly import NSObject_SafeExpectations // Site Topic Keys private let SiteDictionaryFeedIDKey = "feed_ID" diff --git a/Sources/WordPressKit/Services/PostServiceRemoteXMLRPC+Extended.swift b/Sources/WordPressKit/Services/PostServiceRemoteXMLRPC+Extended.swift index 50265480..098e9e64 100644 --- a/Sources/WordPressKit/Services/PostServiceRemoteXMLRPC+Extended.swift +++ b/Sources/WordPressKit/Services/PostServiceRemoteXMLRPC+Extended.swift @@ -1,5 +1,5 @@ import Foundation -import wpxmlrpc +@_implementationOnly import wpxmlrpc extension PostServiceRemoteXMLRPC: PostServiceRemoteExtended { public func post(withID postID: Int) async throws -> RemotePost { diff --git a/Sources/WordPressKit/Services/SharingServiceRemote.swift b/Sources/WordPressKit/Services/SharingServiceRemote.swift index a6bd0e6e..8be0157a 100644 --- a/Sources/WordPressKit/Services/SharingServiceRemote.swift +++ b/Sources/WordPressKit/Services/SharingServiceRemote.swift @@ -1,5 +1,5 @@ import Foundation -import NSObject_SafeExpectations +@_implementationOnly import NSObject_SafeExpectations /// SharingServiceRemote is responsible for wrangling the REST API calls related to /// publiczice services, publicize connections, and keyring connections. From a3000c4d668f0b7db76691ab7f1219fe9370fc10 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 12 Jul 2024 10:32:48 -0400 Subject: [PATCH 08/97] Prefix extensions --- Sources/WordPressShared/NSString+XMLExtensions.h | 2 +- Sources/WordPressShared/NSString+XMLExtensions.m | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/WordPressShared/NSString+XMLExtensions.h b/Sources/WordPressShared/NSString+XMLExtensions.h index 046cc7a6..f2de4533 100644 --- a/Sources/WordPressShared/NSString+XMLExtensions.h +++ b/Sources/WordPressShared/NSString+XMLExtensions.h @@ -1,6 +1,6 @@ #import -@interface NSString (XMLExtensions) +@interface NSString (WPKitXMLExtensions) + (NSString *)wpkit_encodeXMLCharactersIn : (NSString *)source; + (NSString *)wpkit_decodeXMLCharactersIn : (NSString *)source; diff --git a/Sources/WordPressShared/NSString+XMLExtensions.m b/Sources/WordPressShared/NSString+XMLExtensions.m index 0738555d..19ee5fb7 100644 --- a/Sources/WordPressShared/NSString+XMLExtensions.m +++ b/Sources/WordPressShared/NSString+XMLExtensions.m @@ -295,7 +295,7 @@ }; -@implementation NSString (XMLExtensions) +@implementation NSString (WPKitXMLExtensions) + (NSString *)wpkit_encodeXMLCharactersIn : (NSString *)source { if (![source isKindOfClass:[NSString class]] || !source) From d32ce39dff3b46b7b767a8a8b6c83a4b511c44e3 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 12 Jul 2024 10:40:13 -0400 Subject: [PATCH 09/97] Fix missing access control modifier --- Sources/CoreAPI/WordPressComRestApi.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/CoreAPI/WordPressComRestApi.swift b/Sources/CoreAPI/WordPressComRestApi.swift index 3b59624b..f5937ba6 100644 --- a/Sources/CoreAPI/WordPressComRestApi.swift +++ b/Sources/CoreAPI/WordPressComRestApi.swift @@ -175,7 +175,7 @@ open class WordPressComRestApi: NSObject { } } - @objc func setInvalidTokenHandler(_ handler: @escaping () -> Void) { + @objc open func setInvalidTokenHandler(_ handler: @escaping () -> Void) { invalidTokenHandler = handler } From 0ada092be8266b79e5d49ad165ea9f31825e06f9 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 12 Jul 2024 14:57:04 -0400 Subject: [PATCH 10/97] Remove Alamofire dependency from tests --- Podfile | 1 - Podfile.lock | 6 +-- Tests/CoreAPITests/MultipartFormTests.swift | 45 +++++++-------------- WordPressKit.xcodeproj/project.pbxproj | 2 - 4 files changed, 15 insertions(+), 39 deletions(-) diff --git a/Podfile b/Podfile index 92dd7581..8433c67e 100644 --- a/Podfile +++ b/Podfile @@ -24,7 +24,6 @@ target 'WordPressKitTests' do pod 'OHHTTPStubs', '~> 9.0' pod 'OHHTTPStubs/Swift', '~> 9.0' pod 'OCMock', '~> 3.4' - pod 'Alamofire', '~> 5.0' end abstract_target 'Tools' do diff --git a/Podfile.lock b/Podfile.lock index cdcd076f..178fd356 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -1,5 +1,4 @@ PODS: - - Alamofire (5.8.1) - OCMock (3.9.3) - OHHTTPStubs (9.1.0): - OHHTTPStubs/Default (= 9.1.0) @@ -19,7 +18,6 @@ PODS: - SwiftLint (0.54.0) DEPENDENCIES: - - Alamofire (~> 5.0) - OCMock (~> 3.4) - OHHTTPStubs (~> 9.0) - OHHTTPStubs/Swift (~> 9.0) @@ -27,17 +25,15 @@ DEPENDENCIES: SPEC REPOS: trunk: - - Alamofire - OCMock - OHHTTPStubs - SwiftLint SPEC CHECKSUMS: - Alamofire: 3ca42e259043ee0dc5c0cdd76c4bc568b8e42af7 OCMock: 300b1b1b9155cb6378660b981c2557448830bdc6 OHHTTPStubs: 90eac6d8f2c18317baeca36698523dc67c513831 SwiftLint: c1de071d9d08c8aba837545f6254315bc900e211 -PODFILE CHECKSUM: f2a6a7320f647a36041a34f152598d1549c4a7e1 +PODFILE CHECKSUM: a15d6be1e4b1409ba20fc010b083eb31a737269f COCOAPODS: 1.15.2 diff --git a/Tests/CoreAPITests/MultipartFormTests.swift b/Tests/CoreAPITests/MultipartFormTests.swift index c966ff9d..88d786d9 100644 --- a/Tests/CoreAPITests/MultipartFormTests.swift +++ b/Tests/CoreAPITests/MultipartFormTests.swift @@ -1,5 +1,4 @@ import Foundation -import Alamofire import XCTest import CryptoKit #if SWIFT_PACKAGE @@ -25,14 +24,6 @@ class MutliparFormDataTests: XCTestCase { return Form(fields: fields) } - func formDataUsingAlamofire() throws -> Data { - let formData = MultipartFormData(boundary: "testboundary") - for field in fields { - formData.append(field.content.data(using: .utf8)!, withName: field.name) - } - return try formData.encode() - } - func formData() throws -> Data { try fields .map { @@ -46,40 +37,33 @@ class MutliparFormDataTests: XCTestCase { func testRandomForm() throws { let tempDir = FileManager.default.temporaryDirectory let testData = tempDir.appendingPathComponent("test-form.json") - let afOutput = tempDir.appendingPathComponent("test-form.af.txt") let wpOutput = tempDir.appendingPathComponent("test-form.wp.txt") - let form = Form.random() + let form = Form(fields: [ + .init(name: "key-1", content: "a"), + .init(name: "key-2", content: "b"), + ]) try JSONEncoder().encode(form).write(to: testData) - let afEncoded = try form.formDataUsingAlamofire() - try afEncoded.write(to: afOutput) - let encoded = try form.formData() try encoded.write(to: wpOutput) add(XCTAttachment(contentsOfFile: testData)) - add(XCTAttachment(contentsOfFile: afOutput)) add(XCTAttachment(contentsOfFile: wpOutput)) - XCTAssertEqual(afEncoded, encoded) + let expected = "--testboundary\r\nContent-Disposition: form-data; name=\"key-1\"\r\n\r\na\r\n--testboundary\r\nContent-Disposition: form-data; name=\"key-2\"\r\n\r\nb\r\n--testboundary--\r\n".data(using: .utf8) + XCTAssertEqual(expected, encoded) } func testPlainText() throws { - let af = MultipartFormData() - af.append("hello".data(using: .utf8)!, withName: "world") - af.append("foo".data(using: .utf8)!, withName: "bar") - af.append("the".data(using: .utf8)!, withName: "end") - let afEncoded = try af.encode() - let fields = [ MultipartFormField(text: "hello", name: "world"), MultipartFormField(text: "foo", name: "bar"), MultipartFormField(text: "the", name: "end"), ] - let encoded = try fields.multipartFormDataStream(boundary: af.boundary).readToEnd() - - XCTAssertEqual(afEncoded, encoded) + let encoded = try fields.multipartFormDataStream(boundary: "wpkit.boundary.9d4adfc909a08bfa").readToEnd() + let expected = "--wpkit.boundary.9d4adfc909a08bfa\r\nContent-Disposition: form-data; name=\"world\"\r\n\r\nhello\r\n--wpkit.boundary.9d4adfc909a08bfa\r\nContent-Disposition: form-data; name=\"bar\"\r\n\r\nfoo\r\n--wpkit.boundary.9d4adfc909a08bfa\r\nContent-Disposition: form-data; name=\"end\"\r\n\r\nthe\r\n--wpkit.boundary.9d4adfc909a08bfa--\r\n".data(using: .utf8) + XCTAssertEqual(expected, encoded) } func testEmptyForm() throws { @@ -88,13 +72,12 @@ class MutliparFormDataTests: XCTestCase { } func testOneField() throws { - let af = MultipartFormData() - af.append("hello".data(using: .utf8)!, withName: "world") - let afEncoded = try af.encode() - - let formData = try [MultipartFormField(text: "hello", name: "world")].multipartFormDataStream(boundary: af.boundary).readToEnd() + let formData = try [MultipartFormField(text: "hello", name: "world")] + .multipartFormDataStream(boundary: "wpkit.boundary.9d4adfc909a08bfa") + .readToEnd() - XCTAssertEqual(afEncoded, formData) + let expected = "--wpkit.boundary.9d4adfc909a08bfa\r\nContent-Disposition: form-data; name=\"world\"\r\n\r\nhello\r\n--wpkit.boundary.9d4adfc909a08bfa--\r\n".data(using: .utf8)! + XCTAssertEqual(expected, formData) } func testUploadSmallFile() throws { diff --git a/WordPressKit.xcodeproj/project.pbxproj b/WordPressKit.xcodeproj/project.pbxproj index 58dac7df..f1da6ad7 100644 --- a/WordPressKit.xcodeproj/project.pbxproj +++ b/WordPressKit.xcodeproj/project.pbxproj @@ -3325,13 +3325,11 @@ ); inputPaths = ( "${PODS_ROOT}/Target Support Files/Pods-WordPressKitTests/Pods-WordPressKitTests-frameworks.sh", - "${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework", "${BUILT_PRODUCTS_DIR}/OCMock/OCMock.framework", "${BUILT_PRODUCTS_DIR}/OHHTTPStubs/OHHTTPStubs.framework", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Alamofire.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OCMock.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OHHTTPStubs.framework", ); From 03b2e770c9b00585b8203137d8d99fede809ebc1 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 12 Jul 2024 15:04:58 -0400 Subject: [PATCH 11/97] Deintegrate CocoaPods --- Podfile | 47 ------ Podfile.lock | 39 ----- Tests/CoreAPITests/NonceRetrievalTests.swift | 5 +- .../WordPressComOAuthClientTests.swift | 5 +- .../WordPressComRestApiTests+Locale.swift | 5 +- .../WordPressComRestApiTests.swift | 6 +- Tests/CoreAPITests/WordPressOrgAPITests.swift | 5 +- .../WordPressOrgRestApiTests.swift | 5 +- .../WordPressOrgXMLRPCApiTests.swift | 5 +- .../WordPressOrgXMLRPCValidatorTests.swift | 5 +- .../Tests/ActivityServiceRemoteTests.swift | 2 + .../AnnouncementServiceRemoteTests.swift | 1 + ...lockEditorSettingsServiceRemoteTests.swift | 2 + .../BloggingPromptsServiceRemoteTests.swift | 1 + .../CommentServiceRemoteREST+APIv2Tests.swift | 1 + .../Tests/DashboardServiceRemoteTests.swift | 1 + .../Tests/DomainsServiceRemoteRESTTests.swift | 1 + .../Tests/MediaLibraryTestSupport.swift | 1 + .../StatsDotComFollowersInsightTests.swift | 2 +- .../Tests/PluginDirectoryTests.swift | 2 + ...PostServiceRemote+FetchEndpointTests.swift | 1 + .../Tests/ReaderSiteServiceRemoteTests.swift | 2 + .../Tests/RemoteTestCase.swift | 4 +- ...elfHostedPluginManagementClientTests.swift | 1 + .../Utilities/FeatureFlagRemoteTests.swift | 2 + .../Tests/Utilities/LoggingTests.m | 13 ++ .../Utilities/URLSessionHelperTests.swift | 1 + .../WordPressComServiceRemoteRestTests.swift | 1 + WordPressKit.xcodeproj/project.pbxproj | 137 ++++++------------ .../contents.xcworkspacedata | 2 +- .../xcshareddata/swiftpm/Package.resolved | 50 +++++++ .../contents.xcworkspacedata | 10 -- .../xcshareddata/IDEWorkspaceChecks.plist | 8 - 33 files changed, 138 insertions(+), 235 deletions(-) delete mode 100644 Podfile delete mode 100644 Podfile.lock create mode 100644 WordPressKit.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved delete mode 100644 WordPressKit.xcworkspace/contents.xcworkspacedata delete mode 100644 WordPressKit.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Podfile b/Podfile deleted file mode 100644 index 8433c67e..00000000 --- a/Podfile +++ /dev/null @@ -1,47 +0,0 @@ -# frozen_string_literal: true - -source 'https://cdn.cocoapods.org/' - -inhibit_all_warnings! -use_frameworks! - -APP_IOS_DEPLOYMENT_TARGET = Gem::Version.new('13.0') - -platform :ios, APP_IOS_DEPLOYMENT_TARGET - -def swiftlint_version - require 'yaml' - - YAML.load_file('.swiftlint.yml')['swiftlint_version'] -end - -## WordPress Kit -## ============= - -target 'WordPressKitTests' do - project 'WordPressKit.xcodeproj' - - pod 'OHHTTPStubs', '~> 9.0' - pod 'OHHTTPStubs/Swift', '~> 9.0' - pod 'OCMock', '~> 3.4' -end - -abstract_target 'Tools' do - pod 'SwiftLint', swiftlint_version -end - -# Let Pods targets inherit deployment target from the app -post_install do |installer| - installer.pods_project.targets.each do |target| - target.build_configurations.each do |configuration| - ios_deployment_key = 'IPHONEOS_DEPLOYMENT_TARGET' - pod_ios_deployment_target = Gem::Version.new(configuration.build_settings[ios_deployment_key]) - configuration.build_settings.delete(ios_deployment_key) if pod_ios_deployment_target <= APP_IOS_DEPLOYMENT_TARGET - end - end - - yellow_marker = "\033[33m" - reset_marker = "\033[0m" - puts "#{yellow_marker}The abstract target warning below is expected. Feel free to ignore - it.#{reset_marker}" -end diff --git a/Podfile.lock b/Podfile.lock deleted file mode 100644 index 178fd356..00000000 --- a/Podfile.lock +++ /dev/null @@ -1,39 +0,0 @@ -PODS: - - OCMock (3.9.3) - - OHHTTPStubs (9.1.0): - - OHHTTPStubs/Default (= 9.1.0) - - OHHTTPStubs/Core (9.1.0) - - OHHTTPStubs/Default (9.1.0): - - OHHTTPStubs/Core - - OHHTTPStubs/JSON - - OHHTTPStubs/NSURLSession - - OHHTTPStubs/OHPathHelpers - - OHHTTPStubs/JSON (9.1.0): - - OHHTTPStubs/Core - - OHHTTPStubs/NSURLSession (9.1.0): - - OHHTTPStubs/Core - - OHHTTPStubs/OHPathHelpers (9.1.0) - - OHHTTPStubs/Swift (9.1.0): - - OHHTTPStubs/Default - - SwiftLint (0.54.0) - -DEPENDENCIES: - - OCMock (~> 3.4) - - OHHTTPStubs (~> 9.0) - - OHHTTPStubs/Swift (~> 9.0) - - SwiftLint (= 0.54.0) - -SPEC REPOS: - trunk: - - OCMock - - OHHTTPStubs - - SwiftLint - -SPEC CHECKSUMS: - OCMock: 300b1b1b9155cb6378660b981c2557448830bdc6 - OHHTTPStubs: 90eac6d8f2c18317baeca36698523dc67c513831 - SwiftLint: c1de071d9d08c8aba837545f6254315bc900e211 - -PODFILE CHECKSUM: a15d6be1e4b1409ba20fc010b083eb31a737269f - -COCOAPODS: 1.15.2 diff --git a/Tests/CoreAPITests/NonceRetrievalTests.swift b/Tests/CoreAPITests/NonceRetrievalTests.swift index c27c8cd1..eb0f54a9 100644 --- a/Tests/CoreAPITests/NonceRetrievalTests.swift +++ b/Tests/CoreAPITests/NonceRetrievalTests.swift @@ -1,12 +1,9 @@ import Foundation import XCTest import OHHTTPStubs -#if SWIFT_PACKAGE -@testable import CoreAPI import OHHTTPStubsSwift -#else + @testable import WordPressKit -#endif class NonceRetrievalTests: XCTestCase { diff --git a/Tests/CoreAPITests/WordPressComOAuthClientTests.swift b/Tests/CoreAPITests/WordPressComOAuthClientTests.swift index 37e1c0af..f5feb7ce 100644 --- a/Tests/CoreAPITests/WordPressComOAuthClientTests.swift +++ b/Tests/CoreAPITests/WordPressComOAuthClientTests.swift @@ -1,12 +1,9 @@ import Foundation import XCTest import OHHTTPStubs -#if SWIFT_PACKAGE -@testable import CoreAPI import OHHTTPStubsSwift -#else + @testable import WordPressKit -#endif class WordPressComOAuthClientTests: XCTestCase { diff --git a/Tests/CoreAPITests/WordPressComRestApiTests+Locale.swift b/Tests/CoreAPITests/WordPressComRestApiTests+Locale.swift index b5b4d56e..77a12077 100644 --- a/Tests/CoreAPITests/WordPressComRestApiTests+Locale.swift +++ b/Tests/CoreAPITests/WordPressComRestApiTests+Locale.swift @@ -1,11 +1,8 @@ import XCTest import OHHTTPStubs -#if SWIFT_PACKAGE -@testable import CoreAPI import OHHTTPStubsSwift -#else + @testable import WordPressKit -#endif extension WordPressComRestApiTests { diff --git a/Tests/CoreAPITests/WordPressComRestApiTests.swift b/Tests/CoreAPITests/WordPressComRestApiTests.swift index 933f0a20..83cca189 100644 --- a/Tests/CoreAPITests/WordPressComRestApiTests.swift +++ b/Tests/CoreAPITests/WordPressComRestApiTests.swift @@ -1,12 +1,8 @@ import XCTest import OHHTTPStubs -#if SWIFT_PACKAGE -import APIInterface -@testable import CoreAPI import OHHTTPStubsSwift -#else + @testable import WordPressKit -#endif class WordPressComRestApiTests: XCTestCase { diff --git a/Tests/CoreAPITests/WordPressOrgAPITests.swift b/Tests/CoreAPITests/WordPressOrgAPITests.swift index 6b3a6b31..28c95fdc 100644 --- a/Tests/CoreAPITests/WordPressOrgAPITests.swift +++ b/Tests/CoreAPITests/WordPressOrgAPITests.swift @@ -1,11 +1,8 @@ import XCTest import OHHTTPStubs -#if SWIFT_PACKAGE -@testable import CoreAPI import OHHTTPStubsSwift -#else + @testable import WordPressKit -#endif class WordPressOrgAPITests: XCTestCase { diff --git a/Tests/CoreAPITests/WordPressOrgRestApiTests.swift b/Tests/CoreAPITests/WordPressOrgRestApiTests.swift index 595d2c5d..d70cacb7 100644 --- a/Tests/CoreAPITests/WordPressOrgRestApiTests.swift +++ b/Tests/CoreAPITests/WordPressOrgRestApiTests.swift @@ -1,11 +1,8 @@ import XCTest import OHHTTPStubs -#if SWIFT_PACKAGE -@testable import CoreAPI import OHHTTPStubsSwift -#else + @testable import WordPressKit -#endif class WordPressOrgRestApiTests: XCTestCase { diff --git a/Tests/CoreAPITests/WordPressOrgXMLRPCApiTests.swift b/Tests/CoreAPITests/WordPressOrgXMLRPCApiTests.swift index b198c5d0..332b6651 100644 --- a/Tests/CoreAPITests/WordPressOrgXMLRPCApiTests.swift +++ b/Tests/CoreAPITests/WordPressOrgXMLRPCApiTests.swift @@ -1,12 +1,9 @@ import XCTest import OHHTTPStubs import wpxmlrpc -#if SWIFT_PACKAGE -@testable import CoreAPI import OHHTTPStubsSwift -#else + @testable import WordPressKit -#endif class WordPressOrgXMLRPCApiTests: XCTestCase { diff --git a/Tests/CoreAPITests/WordPressOrgXMLRPCValidatorTests.swift b/Tests/CoreAPITests/WordPressOrgXMLRPCValidatorTests.swift index 3a79b643..0490d90d 100644 --- a/Tests/CoreAPITests/WordPressOrgXMLRPCValidatorTests.swift +++ b/Tests/CoreAPITests/WordPressOrgXMLRPCValidatorTests.swift @@ -1,11 +1,8 @@ import XCTest import OHHTTPStubs -#if SWIFT_PACKAGE -@testable import CoreAPI import OHHTTPStubsSwift -#else + @testable import WordPressKit -#endif final class WordPressOrgXMLRPCValidatorTests: XCTestCase { diff --git a/Tests/WordPressKitTests/Tests/ActivityServiceRemoteTests.swift b/Tests/WordPressKitTests/Tests/ActivityServiceRemoteTests.swift index 328a64e8..7661bc5f 100644 --- a/Tests/WordPressKitTests/Tests/ActivityServiceRemoteTests.swift +++ b/Tests/WordPressKitTests/Tests/ActivityServiceRemoteTests.swift @@ -1,6 +1,8 @@ import Foundation import OHHTTPStubs +import OHHTTPStubsSwift import XCTest + @testable import WordPressKit class ActivityServiceRemoteTests: RemoteTestCase, RESTTestable { diff --git a/Tests/WordPressKitTests/Tests/AnnouncementServiceRemoteTests.swift b/Tests/WordPressKitTests/Tests/AnnouncementServiceRemoteTests.swift index bbcac5fe..e5fcf5f9 100644 --- a/Tests/WordPressKitTests/Tests/AnnouncementServiceRemoteTests.swift +++ b/Tests/WordPressKitTests/Tests/AnnouncementServiceRemoteTests.swift @@ -1,6 +1,7 @@ import Foundation import XCTest import OHHTTPStubs +import OHHTTPStubsSwift @testable import WordPressKit diff --git a/Tests/WordPressKitTests/Tests/BlockEditorSettingsServiceRemoteTests.swift b/Tests/WordPressKitTests/Tests/BlockEditorSettingsServiceRemoteTests.swift index e81a8afc..39f37708 100644 --- a/Tests/WordPressKitTests/Tests/BlockEditorSettingsServiceRemoteTests.swift +++ b/Tests/WordPressKitTests/Tests/BlockEditorSettingsServiceRemoteTests.swift @@ -1,5 +1,7 @@ import XCTest import OHHTTPStubs +import OHHTTPStubsSwift + @testable import WordPressKit class BlockEditorSettingsServiceRemoteTests: XCTestCase { diff --git a/Tests/WordPressKitTests/Tests/BloggingPromptsServiceRemoteTests.swift b/Tests/WordPressKitTests/Tests/BloggingPromptsServiceRemoteTests.swift index 3aa2d3b1..844bd900 100644 --- a/Tests/WordPressKitTests/Tests/BloggingPromptsServiceRemoteTests.swift +++ b/Tests/WordPressKitTests/Tests/BloggingPromptsServiceRemoteTests.swift @@ -1,5 +1,6 @@ import XCTest import OHHTTPStubs +import OHHTTPStubsSwift @testable import WordPressKit diff --git a/Tests/WordPressKitTests/Tests/CommentServiceRemoteREST+APIv2Tests.swift b/Tests/WordPressKitTests/Tests/CommentServiceRemoteREST+APIv2Tests.swift index 1cdb540e..5d9692bb 100644 --- a/Tests/WordPressKitTests/Tests/CommentServiceRemoteREST+APIv2Tests.swift +++ b/Tests/WordPressKitTests/Tests/CommentServiceRemoteREST+APIv2Tests.swift @@ -1,6 +1,7 @@ import Foundation import XCTest import OHHTTPStubs +import OHHTTPStubsSwift @testable import WordPressKit diff --git a/Tests/WordPressKitTests/Tests/DashboardServiceRemoteTests.swift b/Tests/WordPressKitTests/Tests/DashboardServiceRemoteTests.swift index 8e6e60c0..401fe472 100644 --- a/Tests/WordPressKitTests/Tests/DashboardServiceRemoteTests.swift +++ b/Tests/WordPressKitTests/Tests/DashboardServiceRemoteTests.swift @@ -1,5 +1,6 @@ import XCTest import OHHTTPStubs +import OHHTTPStubsSwift @testable import WordPressKit diff --git a/Tests/WordPressKitTests/Tests/DomainsServiceRemoteRESTTests.swift b/Tests/WordPressKitTests/Tests/DomainsServiceRemoteRESTTests.swift index 5e5f0289..0f3870f2 100644 --- a/Tests/WordPressKitTests/Tests/DomainsServiceRemoteRESTTests.swift +++ b/Tests/WordPressKitTests/Tests/DomainsServiceRemoteRESTTests.swift @@ -1,6 +1,7 @@ import Foundation import XCTest import OHHTTPStubs +import OHHTTPStubsSwift @testable import WordPressKit diff --git a/Tests/WordPressKitTests/Tests/MediaLibraryTestSupport.swift b/Tests/WordPressKitTests/Tests/MediaLibraryTestSupport.swift index 85d7d87a..da2091a9 100644 --- a/Tests/WordPressKitTests/Tests/MediaLibraryTestSupport.swift +++ b/Tests/WordPressKitTests/Tests/MediaLibraryTestSupport.swift @@ -2,6 +2,7 @@ import Foundation import XCTest import UniformTypeIdentifiers import OHHTTPStubs +import OHHTTPStubsSwift import wpxmlrpc /// This type acts like a WordPress Media Library. It can be used in test cases to stub loading media library content diff --git a/Tests/WordPressKitTests/Tests/Models/Stats/V2/Insights/StatsDotComFollowersInsightTests.swift b/Tests/WordPressKitTests/Tests/Models/Stats/V2/Insights/StatsDotComFollowersInsightTests.swift index fe9a1847..440a9ac0 100644 --- a/Tests/WordPressKitTests/Tests/Models/Stats/V2/Insights/StatsDotComFollowersInsightTests.swift +++ b/Tests/WordPressKitTests/Tests/Models/Stats/V2/Insights/StatsDotComFollowersInsightTests.swift @@ -115,7 +115,7 @@ private extension StatsDotComFollowersInsightTests { guard var components = URLComponents(string: urlString) else { return nil } components.query = "d=mm&s=60" - return try? components.asURL() + return components.url } } diff --git a/Tests/WordPressKitTests/Tests/PluginDirectoryTests.swift b/Tests/WordPressKitTests/Tests/PluginDirectoryTests.swift index 88671778..13ad32ab 100644 --- a/Tests/WordPressKitTests/Tests/PluginDirectoryTests.swift +++ b/Tests/WordPressKitTests/Tests/PluginDirectoryTests.swift @@ -1,5 +1,7 @@ import XCTest import OHHTTPStubs +import OHHTTPStubsSwift + @testable import WordPressKit class PluginDirectoryTests: XCTestCase { diff --git a/Tests/WordPressKitTests/Tests/ReaderPostServiceRemote+FetchEndpointTests.swift b/Tests/WordPressKitTests/Tests/ReaderPostServiceRemote+FetchEndpointTests.swift index 3d96bf21..90fa182a 100644 --- a/Tests/WordPressKitTests/Tests/ReaderPostServiceRemote+FetchEndpointTests.swift +++ b/Tests/WordPressKitTests/Tests/ReaderPostServiceRemote+FetchEndpointTests.swift @@ -1,6 +1,7 @@ import Foundation import XCTest import OHHTTPStubs +import OHHTTPStubsSwift @testable import WordPressKit diff --git a/Tests/WordPressKitTests/Tests/ReaderSiteServiceRemoteTests.swift b/Tests/WordPressKitTests/Tests/ReaderSiteServiceRemoteTests.swift index ca9e8027..17379702 100644 --- a/Tests/WordPressKitTests/Tests/ReaderSiteServiceRemoteTests.swift +++ b/Tests/WordPressKitTests/Tests/ReaderSiteServiceRemoteTests.swift @@ -1,5 +1,7 @@ import XCTest import OHHTTPStubs +import OHHTTPStubsSwift + @testable import WordPressKit class ReaderSiteServiceRemoteTests: XCTestCase { diff --git a/Tests/WordPressKitTests/Tests/RemoteTestCase.swift b/Tests/WordPressKitTests/Tests/RemoteTestCase.swift index a55165b7..954f07c8 100644 --- a/Tests/WordPressKitTests/Tests/RemoteTestCase.swift +++ b/Tests/WordPressKitTests/Tests/RemoteTestCase.swift @@ -2,6 +2,8 @@ import BuildkiteTestCollector import Foundation import XCTest import OHHTTPStubs +import OHHTTPStubsSwift + @testable import WordPressKit /// Base class for all remote unit tests. @@ -67,7 +69,7 @@ extension RemoteTestCase { if contentType != .NoContentType { headers = ["Content-Type" as NSObject: contentType.rawValue as AnyObject] } - return OHHTTPStubs.fixture(filePath: stubPath, status: status, headers: headers) + return OHHTTPStubsSwift.fixture(filePath: stubPath, status: status, headers: headers) } } diff --git a/Tests/WordPressKitTests/Tests/SelfHostedPluginManagementClientTests.swift b/Tests/WordPressKitTests/Tests/SelfHostedPluginManagementClientTests.swift index 5d278b7e..3258f87d 100644 --- a/Tests/WordPressKitTests/Tests/SelfHostedPluginManagementClientTests.swift +++ b/Tests/WordPressKitTests/Tests/SelfHostedPluginManagementClientTests.swift @@ -1,6 +1,7 @@ import Foundation import XCTest import OHHTTPStubs +import OHHTTPStubsSwift @testable import WordPressKit diff --git a/Tests/WordPressKitTests/Tests/Utilities/FeatureFlagRemoteTests.swift b/Tests/WordPressKitTests/Tests/Utilities/FeatureFlagRemoteTests.swift index 602d8957..f9e46c63 100644 --- a/Tests/WordPressKitTests/Tests/Utilities/FeatureFlagRemoteTests.swift +++ b/Tests/WordPressKitTests/Tests/Utilities/FeatureFlagRemoteTests.swift @@ -1,5 +1,7 @@ import XCTest import OHHTTPStubs +import OHHTTPStubsSwift + @testable import WordPressKit class FeatureFlagRemoteTests: RemoteTestCase, RESTTestable { diff --git a/Tests/WordPressKitTests/Tests/Utilities/LoggingTests.m b/Tests/WordPressKitTests/Tests/Utilities/LoggingTests.m index 62b06880..a884af94 100644 --- a/Tests/WordPressKitTests/Tests/Utilities/LoggingTests.m +++ b/Tests/WordPressKitTests/Tests/Utilities/LoggingTests.m @@ -30,6 +30,19 @@ - (void)logError:(NSString *)str [self.errorLogs addObject:str]; } +- (void)logDebug:(nonnull NSString *)str { + +} + +- (void)logVerbose:(nonnull NSString *)str { + +} + +- (void)logWarning:(nonnull NSString *)str { + +} + + @end @interface ObjCLoggingTest : XCTestCase diff --git a/Tests/WordPressKitTests/Tests/Utilities/URLSessionHelperTests.swift b/Tests/WordPressKitTests/Tests/Utilities/URLSessionHelperTests.swift index ebe0b154..8f2096ad 100644 --- a/Tests/WordPressKitTests/Tests/Utilities/URLSessionHelperTests.swift +++ b/Tests/WordPressKitTests/Tests/Utilities/URLSessionHelperTests.swift @@ -2,6 +2,7 @@ import Foundation import CryptoKit import XCTest import OHHTTPStubs +import OHHTTPStubsSwift @testable import WordPressKit diff --git a/Tests/WordPressKitTests/Tests/WordPressComServiceRemoteRestTests.swift b/Tests/WordPressKitTests/Tests/WordPressComServiceRemoteRestTests.swift index 37d1f508..72f3781b 100644 --- a/Tests/WordPressKitTests/Tests/WordPressComServiceRemoteRestTests.swift +++ b/Tests/WordPressKitTests/Tests/WordPressComServiceRemoteRestTests.swift @@ -1,6 +1,7 @@ import XCTest import WordPressKit import OHHTTPStubs +import OHHTTPStubsSwift class WordPressComServiceRemoteRestTests: XCTestCase { diff --git a/WordPressKit.xcodeproj/project.pbxproj b/WordPressKit.xcodeproj/project.pbxproj index f1da6ad7..0b117124 100644 --- a/WordPressKit.xcodeproj/project.pbxproj +++ b/WordPressKit.xcodeproj/project.pbxproj @@ -20,6 +20,9 @@ 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 */; }; + 0C363D422C41B455004E241D /* OCMock in Frameworks */ = {isa = PBXBuildFile; productRef = 0C363D412C41B455004E241D /* OCMock */; }; + 0C363D452C41B468004E241D /* OHHTTPStubs in Frameworks */ = {isa = PBXBuildFile; productRef = 0C363D442C41B468004E241D /* OHHTTPStubs */; }; + 0C363D472C41B468004E241D /* OHHTTPStubsSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 0C363D462C41B468004E241D /* OHHTTPStubsSwift */; }; 0C674E302BF3A91300F3B3D4 /* JetpackAIServiceRemote.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C674E2F2BF3A91300F3B3D4 /* JetpackAIServiceRemote.swift */; }; 0C938A062C416789009BA7B2 /* Secret.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C938A052C416789009BA7B2 /* Secret.swift */; }; 0C938A092C4167BC009BA7B2 /* NSString+XMLExtensions.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C938A072C4167BB009BA7B2 /* NSString+XMLExtensions.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -67,7 +70,6 @@ 1DF972BF29B107E7007A72BC /* videopress-private-video.json in Resources */ = {isa = PBXBuildFile; fileRef = 1DF972BC29B107E7007A72BC /* videopress-private-video.json */; }; 1DF972C029B107E7007A72BC /* videopress-public-video.json in Resources */ = {isa = PBXBuildFile; fileRef = 1DF972BD29B107E7007A72BC /* videopress-public-video.json */; }; 1DF972C129B107E7007A72BC /* videopress-site-default-video.json in Resources */ = {isa = PBXBuildFile; fileRef = 1DF972BE29B107E7007A72BC /* videopress-site-default-video.json */; }; - 240315B0A1D6C2B981572B5B /* Pods_WordPressKitTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ED05C8FF3E61D93CE5BA527E /* Pods_WordPressKitTests.framework */; }; 24ADA24E24F9B32D001B5DAE /* FeatureFlagSerializationTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24ADA24D24F9B32D001B5DAE /* FeatureFlagSerializationTest.swift */; }; 264E09B52AD259FF004B5A5F /* WordPressComOAuthRequestChallenge.json in Resources */ = {isa = PBXBuildFile; fileRef = 264E09B42AD259FF004B5A5F /* WordPressComOAuthRequestChallenge.json */; }; 264E09B72AD25ED9004B5A5F /* WordPressComOAuthAuthenticateSignature.json in Resources */ = {isa = PBXBuildFile; fileRef = 264E09B62AD25ED9004B5A5F /* WordPressComOAuthAuthenticateSignature.json */; }; @@ -846,7 +848,6 @@ 264E09B42AD259FF004B5A5F /* WordPressComOAuthRequestChallenge.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = WordPressComOAuthRequestChallenge.json; sourceTree = ""; }; 264E09B62AD25ED9004B5A5F /* WordPressComOAuthAuthenticateSignature.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = WordPressComOAuthAuthenticateSignature.json; sourceTree = ""; }; 264E09B82AD2709A004B5A5F /* WordPressComOAuthNeedsWebauthnMFA.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = WordPressComOAuthNeedsWebauthnMFA.json; 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 = ""; }; 3236F77724AE34B40088E8F3 /* ReaderTopicServiceRemote+Interests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ReaderTopicServiceRemote+Interests.swift"; sourceTree = ""; }; 3236F79924AE406D0088E8F3 /* ReaderTopicServiceRemote+InterestsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ReaderTopicServiceRemote+InterestsTests.swift"; sourceTree = ""; }; 3236F79B24AE413A0088E8F3 /* reader-interests-success.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "reader-interests-success.json"; sourceTree = ""; }; @@ -1010,7 +1011,6 @@ 4AE278492B2FC6C600E4D9B1 /* HTTPHeaderValueParserTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HTTPHeaderValueParserTests.swift; sourceTree = ""; }; 4AE7E36A2B9A995500C8CED5 /* AnnouncementServiceRemoteTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnnouncementServiceRemoteTests.swift; sourceTree = ""; }; 4AE7E36C2B9A9BC400C8CED5 /* site-zendesk-metadata-success.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "site-zendesk-metadata-success.json"; sourceTree = ""; }; - 6F2E0CC4FA01B5475A378DA2 /* Pods-WordPressKitTests.release-alpha.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WordPressKitTests.release-alpha.xcconfig"; path = "Pods/Target Support Files/Pods-WordPressKitTests/Pods-WordPressKitTests.release-alpha.xcconfig"; sourceTree = ""; }; 730E869E21E44EFD00753E1A /* WordPressComServiceRemote+SiteVerticals.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WordPressComServiceRemote+SiteVerticals.swift"; sourceTree = ""; }; 731BA83521DECD61000FDFCD /* SiteCreationRequestEncodingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SiteCreationRequestEncodingTests.swift; sourceTree = ""; }; 731BA83721DECD97000FDFCD /* SiteCreationResponseDecodingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SiteCreationResponseDecodingTests.swift; sourceTree = ""; }; @@ -1384,7 +1384,6 @@ B5A4822A20AC6C0B009D95F6 /* WPKitLogging.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WPKitLogging.swift; sourceTree = ""; }; B5A4822C20AC6C19009D95F6 /* WPKitLogging.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WPKitLogging.m; sourceTree = ""; }; B5A4822D20AC6C1A009D95F6 /* WPKitLogging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WPKitLogging.h; sourceTree = ""; }; - B76472D20711B6BE2ACDC332 /* Pods-WordPressKitTests.release-internal.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WordPressKitTests.release-internal.xcconfig"; path = "Pods/Target Support Files/Pods-WordPressKitTests/Pods-WordPressKitTests.release-internal.xcconfig"; sourceTree = ""; }; BA0637EC2492382200AF8419 /* PluginStateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PluginStateTests.swift; sourceTree = ""; }; BA2A78F924A486D300BB6F53 /* SitePluginTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SitePluginTests.swift; sourceTree = ""; }; BA3F138D24A09C87006367A3 /* plugin-install-generic-error.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "plugin-install-generic-error.json"; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.json; }; @@ -1405,7 +1404,6 @@ BA9A7F7E24C6895600925E81 /* plugin-directory-jetpack-beta.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "plugin-directory-jetpack-beta.json"; sourceTree = ""; }; BAB0E36324AD599700B3D22C /* MockPluginStateProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockPluginStateProvider.swift; sourceTree = ""; }; BAFA775524ADAB3C000F0D3A /* MockPluginDirectoryEntryProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockPluginDirectoryEntryProvider.swift; sourceTree = ""; }; - C5953994B3865AF409BA4210 /* Pods-WordPressKitTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WordPressKitTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-WordPressKitTests/Pods-WordPressKitTests.release.xcconfig"; sourceTree = ""; }; C738CAEE28622325001BE107 /* QRLoginServiceRemoteTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRLoginServiceRemoteTests.swift; sourceTree = ""; }; C738CAF0286224ED001BE107 /* qrlogin-validate-200.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "qrlogin-validate-200.json"; sourceTree = ""; }; C738CAF2286226D6001BE107 /* qrlogin-validate-400.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "qrlogin-validate-400.json"; sourceTree = ""; }; @@ -1456,7 +1454,6 @@ E6C1E8471EF21FC100D139D9 /* is-passwordless-account-no-account-found.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "is-passwordless-account-no-account-found.json"; sourceTree = ""; }; E6C1E8481EF21FC100D139D9 /* is-passwordless-account-success.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "is-passwordless-account-success.json"; sourceTree = ""; }; E6D0EE611F7EF9CE0064D3FC /* AccountServiceRemoteREST+SocialService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AccountServiceRemoteREST+SocialService.swift"; sourceTree = ""; }; - ED05C8FF3E61D93CE5BA527E /* Pods_WordPressKitTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_WordPressKitTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; F181EA0127184D3C00F26141 /* ProductServiceRemote.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProductServiceRemote.swift; sourceTree = ""; }; F194E1222417ED9F00874408 /* AtomicAuthenticationServiceRemoteTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AtomicAuthenticationServiceRemoteTests.swift; sourceTree = ""; }; F194E1242417EE7E00874408 /* atomic-get-auth-cookie-success.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "atomic-get-auth-cookie-success.json"; sourceTree = ""; }; @@ -1567,9 +1564,11 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 0C363D452C41B468004E241D /* OHHTTPStubs in Frameworks */, + 0C363D472C41B468004E241D /* OHHTTPStubsSwift in Frameworks */, 3FB8642C2888089F003A86BE /* BuildkiteTestCollector in Frameworks */, 9368C7851EC5EF1B0092CE8E /* WordPressKit.framework in Frameworks */, - 240315B0A1D6C2B981572B5B /* Pods_WordPressKitTests.framework in Frameworks */, + 0C363D422C41B455004E241D /* OCMock in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1653,14 +1652,6 @@ path = "Jetpack Scan"; sourceTree = ""; }; - 38C6ABE94A27A12C9C4AD19D /* Frameworks */ = { - isa = PBXGroup; - children = ( - ED05C8FF3E61D93CE5BA527E /* Pods_WordPressKitTests.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; 3F3195AB266FF91100397EE7 /* Plans */ = { isa = PBXGroup; children = ( @@ -2335,8 +2326,6 @@ 0C3A2A412A2E7BA500FD91D6 /* CHANGELOG.md */, FF20AD2120B8471A00082398 /* WordPressKit.podspec */, 9368C77C1EC5EF1B0092CE8E /* Products */, - 38C6ABE94A27A12C9C4AD19D /* Frameworks */, - E5EA953F7DD505CCED2E44CD /* Pods */, ); sourceTree = ""; }; @@ -2678,17 +2667,6 @@ path = "QR Login"; sourceTree = ""; }; - E5EA953F7DD505CCED2E44CD /* Pods */ = { - isa = PBXGroup; - children = ( - 264F5C834541BBF2018F4964 /* Pods-WordPressKitTests.debug.xcconfig */, - C5953994B3865AF409BA4210 /* Pods-WordPressKitTests.release.xcconfig */, - 6F2E0CC4FA01B5475A378DA2 /* Pods-WordPressKitTests.release-alpha.xcconfig */, - B76472D20711B6BE2ACDC332 /* Pods-WordPressKitTests.release-internal.xcconfig */, - ); - name = Pods; - sourceTree = ""; - }; F3FF8A1A279C86AF00E5C90F /* Models */ = { isa = PBXGroup; children = ( @@ -2860,7 +2838,6 @@ 9368C7761EC5EF1B0092CE8E /* Sources */, 9368C7771EC5EF1B0092CE8E /* Frameworks */, 9368C7791EC5EF1B0092CE8E /* Resources */, - 3F391E242B577AD7007975C4 /* SwiftLint */, ); buildRules = ( ); @@ -2879,11 +2856,9 @@ isa = PBXNativeTarget; buildConfigurationList = 9368C7921EC5EF1B0092CE8E /* Build configuration list for PBXNativeTarget "WordPressKitTests" */; buildPhases = ( - 07D73601D3D9744A82A5C64A /* [CP] Check Pods Manifest.lock */, 9368C7801EC5EF1B0092CE8E /* Sources */, 9368C7811EC5EF1B0092CE8E /* Frameworks */, 9368C7821EC5EF1B0092CE8E /* Resources */, - B07A9DD36A28DB40846D1682 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -2893,6 +2868,9 @@ name = WordPressKitTests; packageProductDependencies = ( 3FB8642B2888089F003A86BE /* BuildkiteTestCollector */, + 0C363D412C41B455004E241D /* OCMock */, + 0C363D442C41B468004E241D /* OHHTTPStubs */, + 0C363D462C41B468004E241D /* OHHTTPStubsSwift */, ); productName = WordPressKitTests; productReference = 9368C7841EC5EF1B0092CE8E /* WordPressKitTests.xctest */; @@ -2933,6 +2911,8 @@ 3FB8642A2888089F003A86BE /* XCRemoteSwiftPackageReference "test-collector-swift" */, 0CCD4C5D2C41711800B53F9A /* XCRemoteSwiftPackageReference "NSObject-SafeExpectations" */, 0CCD4C602C41712800B53F9A /* XCRemoteSwiftPackageReference "wpxmlrpc" */, + 0C363D402C41B455004E241D /* XCRemoteSwiftPackageReference "ocmock" */, + 0C363D432C41B468004E241D /* XCRemoteSwiftPackageReference "OHHTTPStubs" */, ); productRefGroup = 9368C77C1EC5EF1B0092CE8E /* Products */; projectDirPath = ""; @@ -3280,66 +3260,6 @@ }; /* End PBXResourcesBuildPhase section */ -/* Begin PBXShellScriptBuildPhase section */ - 07D73601D3D9744A82A5C64A /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-WordPressKitTests-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; - 3F391E242B577AD7007975C4 /* SwiftLint */ = { - isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - ); - name = SwiftLint; - outputFileListPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "./Pods/SwiftLint/swiftlint lint\n"; - }; - B07A9DD36A28DB40846D1682 /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-WordPressKitTests/Pods-WordPressKitTests-frameworks.sh", - "${BUILT_PRODUCTS_DIR}/OCMock/OCMock.framework", - "${BUILT_PRODUCTS_DIR}/OHHTTPStubs/OHHTTPStubs.framework", - ); - name = "[CP] Embed Pods Frameworks"; - outputPaths = ( - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OCMock.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OHHTTPStubs.framework", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-WordPressKitTests/Pods-WordPressKitTests-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; -/* End PBXShellScriptBuildPhase section */ - /* Begin PBXSourcesBuildPhase section */ 9368C7761EC5EF1B0092CE8E /* Sources */ = { isa = PBXSourcesBuildPhase; @@ -3937,7 +3857,6 @@ }; 9368C7931EC5EF1B0092CE8E /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 264F5C834541BBF2018F4964 /* Pods-WordPressKitTests.debug.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "${inherited}"; CLANG_ENABLE_MODULES = YES; @@ -3962,7 +3881,6 @@ }; 9368C7941EC5EF1B0092CE8E /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = C5953994B3865AF409BA4210 /* Pods-WordPressKitTests.release.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "${inherited}"; CLANG_ENABLE_MODULES = YES; @@ -4077,7 +3995,6 @@ }; 93D436191EC638A100626832 /* Release-Internal */ = { isa = XCBuildConfiguration; - baseConfigurationReference = B76472D20711B6BE2ACDC332 /* Pods-WordPressKitTests.release-internal.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "${inherited}"; CLANG_ENABLE_MODULES = YES; @@ -4192,7 +4109,6 @@ }; 93D4361C1EC638A800626832 /* Release-Alpha */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 6F2E0CC4FA01B5475A378DA2 /* Pods-WordPressKitTests.release-alpha.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "${inherited}"; CLANG_ENABLE_MODULES = YES; @@ -4253,6 +4169,22 @@ /* End XCConfigurationList section */ /* Begin XCRemoteSwiftPackageReference section */ + 0C363D402C41B455004E241D /* XCRemoteSwiftPackageReference "ocmock" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/erikdoe/ocmock"; + requirement = { + kind = revision; + revision = 2c0bfd373289f4a7716db5d6db471640f91a6507; + }; + }; + 0C363D432C41B468004E241D /* XCRemoteSwiftPackageReference "OHHTTPStubs" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/AliSoftware/OHHTTPStubs"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 9.1.0; + }; + }; 0CCD4C5D2C41711800B53F9A /* XCRemoteSwiftPackageReference "NSObject-SafeExpectations" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/wordpress-mobile/NSObject-SafeExpectations"; @@ -4280,6 +4212,21 @@ /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ + 0C363D412C41B455004E241D /* OCMock */ = { + isa = XCSwiftPackageProductDependency; + package = 0C363D402C41B455004E241D /* XCRemoteSwiftPackageReference "ocmock" */; + productName = OCMock; + }; + 0C363D442C41B468004E241D /* OHHTTPStubs */ = { + isa = XCSwiftPackageProductDependency; + package = 0C363D432C41B468004E241D /* XCRemoteSwiftPackageReference "OHHTTPStubs" */; + productName = OHHTTPStubs; + }; + 0C363D462C41B468004E241D /* OHHTTPStubsSwift */ = { + isa = XCSwiftPackageProductDependency; + package = 0C363D432C41B468004E241D /* XCRemoteSwiftPackageReference "OHHTTPStubs" */; + productName = OHHTTPStubsSwift; + }; 0CCD4C5E2C41711800B53F9A /* NSObject-SafeExpectations */ = { isa = XCSwiftPackageProductDependency; package = 0CCD4C5D2C41711800B53F9A /* XCRemoteSwiftPackageReference "NSObject-SafeExpectations" */; diff --git a/WordPressKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/WordPressKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata index 40656752..919434a6 100644 --- a/WordPressKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ b/WordPressKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -2,6 +2,6 @@ + location = "self:"> diff --git a/WordPressKit.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/WordPressKit.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 00000000..2de2a748 --- /dev/null +++ b/WordPressKit.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,50 @@ +{ + "originHash" : "b3d469737e2fd0687b17812621644caa41a5cfacdd9f16988404acb4c8907fc3", + "pins" : [ + { + "identity" : "nsobject-safeexpectations", + "kind" : "remoteSourceControl", + "location" : "https://github.com/wordpress-mobile/NSObject-SafeExpectations", + "state" : { + "revision" : "eb84d994ab13a153888a19e5b99f536aafa77434", + "version" : "0.0.6" + } + }, + { + "identity" : "ocmock", + "kind" : "remoteSourceControl", + "location" : "https://github.com/erikdoe/ocmock", + "state" : { + "revision" : "2c0bfd373289f4a7716db5d6db471640f91a6507" + } + }, + { + "identity" : "ohhttpstubs", + "kind" : "remoteSourceControl", + "location" : "https://github.com/AliSoftware/OHHTTPStubs", + "state" : { + "revision" : "12f19662426d0434d6c330c6974d53e2eb10ecd9", + "version" : "9.1.0" + } + }, + { + "identity" : "test-collector-swift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/buildkite/test-collector-swift", + "state" : { + "revision" : "631a2400dbe876141a3ef8c7400885907fec7f89", + "version" : "0.4.1" + } + }, + { + "identity" : "wpxmlrpc", + "kind" : "remoteSourceControl", + "location" : "https://github.com/wordpress-mobile/wpxmlrpc", + "state" : { + "revision" : "bfc413d336bdeaab89e62dc483380baa99b2257e", + "version" : "0.10.0" + } + } + ], + "version" : 3 +} diff --git a/WordPressKit.xcworkspace/contents.xcworkspacedata b/WordPressKit.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index c6817f81..00000000 --- a/WordPressKit.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - diff --git a/WordPressKit.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/WordPressKit.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d98100..00000000 --- a/WordPressKit.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - From 6f2c142584f7c321b74b1e0a06a54dd5f2848e60 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 12 Jul 2024 19:40:21 -0400 Subject: [PATCH 12/97] Remove unused files --- .gitignore | 6 +- Package.resolved | 122 ------------------ WordPressKit.podspec | 28 ---- WordPressKit.xcodeproj/project.pbxproj | 4 - .../xcshareddata/swiftpm/Package.resolved | 33 ----- create-xcframeworks.sh | 2 +- 6 files changed, 4 insertions(+), 191 deletions(-) delete mode 100644 Package.resolved delete mode 100644 WordPressKit.podspec delete mode 100644 WordPressKit.xcworkspace/xcshareddata/swiftpm/Package.resolved diff --git a/.gitignore b/.gitignore index 0785d714..a37d2195 100644 --- a/.gitignore +++ b/.gitignore @@ -43,13 +43,13 @@ playground.xcworkspace # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. # Packages/ # Package.pins -# Package.resolved + # *.xcodeproj # # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata # hence it is not needed unless you have added a package configuration file to your project -# .swiftpm - +.swiftpm +Package.resolved .build/ # CocoaPods diff --git a/Package.resolved b/Package.resolved deleted file mode 100644 index a25dc7e5..00000000 --- a/Package.resolved +++ /dev/null @@ -1,122 +0,0 @@ -{ - "pins" : [ - { - "identity" : "alamofire", - "kind" : "remoteSourceControl", - "location" : "https://github.com/Alamofire/Alamofire", - "state" : { - "revision" : "f455c2975872ccd2d9c81594c658af65716e9b9a", - "version" : "5.9.1" - } - }, - { - "identity" : "collectionconcurrencykit", - "kind" : "remoteSourceControl", - "location" : "https://github.com/JohnSundell/CollectionConcurrencyKit.git", - "state" : { - "revision" : "b4f23e24b5a1bff301efc5e70871083ca029ff95", - "version" : "0.2.0" - } - }, - { - "identity" : "cryptoswift", - "kind" : "remoteSourceControl", - "location" : "https://github.com/krzyzanowskim/CryptoSwift.git", - "state" : { - "revision" : "7892a123f7e8d0fe62f9f03728b17bbd4f94df5c", - "version" : "1.8.1" - } - }, - { - "identity" : "ohhttpstubs", - "kind" : "remoteSourceControl", - "location" : "https://github.com/AliSoftware/OHHTTPStubs", - "state" : { - "revision" : "12f19662426d0434d6c330c6974d53e2eb10ecd9", - "version" : "9.1.0" - } - }, - { - "identity" : "sourcekitten", - "kind" : "remoteSourceControl", - "location" : "https://github.com/jpsim/SourceKitten.git", - "state" : { - "revision" : "b6dc09ee51dfb0c66e042d2328c017483a1a5d56", - "version" : "0.34.1" - } - }, - { - "identity" : "swift-argument-parser", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-argument-parser.git", - "state" : { - "revision" : "8f4d2753f0e4778c76d5f05ad16c74f707390531", - "version" : "1.2.3" - } - }, - { - "identity" : "swift-syntax", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-syntax.git", - "state" : { - "revision" : "6ad4ea24b01559dde0773e3d091f1b9e36175036", - "version" : "509.0.2" - } - }, - { - "identity" : "swiftlint", - "kind" : "remoteSourceControl", - "location" : "https://github.com/realm/SwiftLint", - "state" : { - "revision" : "f17a4f9dfb6a6afb0408426354e4180daaf49cee", - "version" : "0.54.0" - } - }, - { - "identity" : "swiftytexttable", - "kind" : "remoteSourceControl", - "location" : "https://github.com/scottrhoyt/SwiftyTextTable.git", - "state" : { - "revision" : "c6df6cf533d120716bff38f8ff9885e1ce2a4ac3", - "version" : "0.9.0" - } - }, - { - "identity" : "swxmlhash", - "kind" : "remoteSourceControl", - "location" : "https://github.com/drmohundro/SWXMLHash.git", - "state" : { - "revision" : "a853604c9e9a83ad9954c7e3d2a565273982471f", - "version" : "7.0.2" - } - }, - { - "identity" : "wordpress-ios-shared", - "kind" : "remoteSourceControl", - "location" : "https://github.com/wordpress-mobile/WordPress-iOS-Shared.git", - "state" : { - "branch" : "mokagio/swiftlint-read-as-dependency", - "revision" : "422950b28f01d7cc11218e7d70a6cd65004d23ae" - } - }, - { - "identity" : "wpxmlrpc", - "kind" : "remoteSourceControl", - "location" : "https://github.com/wordpress-mobile/wpxmlrpc", - "state" : { - "revision" : "bfc413d336bdeaab89e62dc483380baa99b2257e", - "version" : "0.10.0" - } - }, - { - "identity" : "yams", - "kind" : "remoteSourceControl", - "location" : "https://github.com/jpsim/Yams.git", - "state" : { - "revision" : "8a835d918245ca22f36663dd3862138805d7f707", - "version" : "5.1.0" - } - } - ], - "version" : 2 -} diff --git a/WordPressKit.podspec b/WordPressKit.podspec deleted file mode 100644 index 1375a772..00000000 --- a/WordPressKit.podspec +++ /dev/null @@ -1,28 +0,0 @@ -# frozen_string_literal: true - -Pod::Spec.new do |s| - s.name = 'WordPressKit' - s.version = '17.2.0' - - s.summary = 'WordPressKit offers a clean and simple WordPress.com and WordPress.org API.' - s.description = <<-DESC - This framework encapsulates all of the networking calls and entity parsers required to interact - with WordPress.com and WordPress.org endpoints. - DESC - - s.homepage = 'https://github.com/wordpress-mobile/WordPressKit-iOS' - s.license = { type: 'GPLv2', file: 'LICENSE' } - s.author = { 'The WordPress Mobile Team' => 'mobile@wordpress.org' } - - s.platform = :ios, '13.0' - s.swift_version = '5.0' - - s.source = { git: 'https://github.com/wordpress-mobile/WordPressKit-iOS.git', tag: s.version.to_s } - s.source_files = 'Sources/**/*.{h,m,swift}' - # When headers are not specified, then all headers are considered public. - # The only thing left to do is to explicitly specify those that should be private. - s.private_header_files = 'Sources/WordPressKit/Private/*.h' - - s.dependency 'NSObject-SafeExpectations', '~> 0.0.4' - s.dependency 'wpxmlrpc', '~> 0.10' -end diff --git a/WordPressKit.xcodeproj/project.pbxproj b/WordPressKit.xcodeproj/project.pbxproj index 0b117124..8d2efb49 100644 --- a/WordPressKit.xcodeproj/project.pbxproj +++ b/WordPressKit.xcodeproj/project.pbxproj @@ -755,7 +755,6 @@ FEFFD99326C141A800F34231 /* RemoteShareAppContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = FEFFD99226C141A800F34231 /* RemoteShareAppContent.swift */; }; FEFFD99726C158F400F34231 /* share-app-content-success.json in Resources */ = {isa = PBXBuildFile; fileRef = FEFFD99626C158F400F34231 /* share-app-content-success.json */; }; FEFFD99B26C1598F00F34231 /* ShareAppContentServiceRemoteTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FEFFD99A26C1598F00F34231 /* ShareAppContentServiceRemoteTests.swift */; }; - FF20AD2220B8471A00082398 /* WordPressKit.podspec in Resources */ = {isa = PBXBuildFile; fileRef = FF20AD2120B8471A00082398 /* WordPressKit.podspec */; }; FFA4D4AA2423B10A00BF5180 /* WordPressOrgRestApiTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFA4D4A82423B10A00BF5180 /* WordPressOrgRestApiTests.swift */; }; FFA4D4AD2423B1FE00BF5180 /* wp-admin-post-new.html in Resources */ = {isa = PBXBuildFile; fileRef = FFA4D4AC2423B1FE00BF5180 /* wp-admin-post-new.html */; }; FFA4D4B02423B33800BF5180 /* wp-forbidden.json in Resources */ = {isa = PBXBuildFile; fileRef = FFA4D4AE2423B33800BF5180 /* wp-forbidden.json */; }; @@ -1530,7 +1529,6 @@ FEFFD99226C141A800F34231 /* RemoteShareAppContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteShareAppContent.swift; sourceTree = ""; }; FEFFD99626C158F400F34231 /* share-app-content-success.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "share-app-content-success.json"; sourceTree = ""; }; FEFFD99A26C1598F00F34231 /* ShareAppContentServiceRemoteTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareAppContentServiceRemoteTests.swift; sourceTree = ""; }; - FF20AD2120B8471A00082398 /* WordPressKit.podspec */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = WordPressKit.podspec; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; FFA4D4A82423B10A00BF5180 /* WordPressOrgRestApiTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WordPressOrgRestApiTests.swift; sourceTree = ""; }; FFA4D4AC2423B1FE00BF5180 /* wp-admin-post-new.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "wp-admin-post-new.html"; sourceTree = ""; }; FFA4D4AE2423B33800BF5180 /* wp-forbidden.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "wp-forbidden.json"; sourceTree = ""; }; @@ -2324,7 +2322,6 @@ FFE247CD20CB1245002DF3A2 /* LICENSE */, FFE247CC20CB118A002DF3A2 /* README.md */, 0C3A2A412A2E7BA500FD91D6 /* CHANGELOG.md */, - FF20AD2120B8471A00082398 /* WordPressKit.podspec */, 9368C77C1EC5EF1B0092CE8E /* Products */, ); sourceTree = ""; @@ -2930,7 +2927,6 @@ buildActionMask = 2147483647; files = ( FFE247CE20CB1245002DF3A2 /* LICENSE in Resources */, - FF20AD2220B8471A00082398 /* WordPressKit.podspec in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/WordPressKit.xcworkspace/xcshareddata/swiftpm/Package.resolved b/WordPressKit.xcworkspace/xcshareddata/swiftpm/Package.resolved deleted file mode 100644 index a0da8255..00000000 --- a/WordPressKit.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ /dev/null @@ -1,33 +0,0 @@ -{ - "originHash" : "eb780b1913f4e443c08925a87813106f18fbb44ec81075f26b522033a6416964", - "pins" : [ - { - "identity" : "nsobject-safeexpectations", - "kind" : "remoteSourceControl", - "location" : "https://github.com/wordpress-mobile/NSObject-SafeExpectations", - "state" : { - "revision" : "eb84d994ab13a153888a19e5b99f536aafa77434", - "version" : "0.0.6" - } - }, - { - "identity" : "test-collector-swift", - "kind" : "remoteSourceControl", - "location" : "https://github.com/buildkite/test-collector-swift", - "state" : { - "revision" : "6e46839e1a4507ee047acd0896e29b9b278d9e3a", - "version" : "0.4.0" - } - }, - { - "identity" : "wpxmlrpc", - "kind" : "remoteSourceControl", - "location" : "https://github.com/wordpress-mobile/wpxmlrpc", - "state" : { - "revision" : "bfc413d336bdeaab89e62dc483380baa99b2257e", - "version" : "0.10.0" - } - } - ], - "version" : 3 -} diff --git a/create-xcframeworks.sh b/create-xcframeworks.sh index 27651d7f..97317259 100755 --- a/create-xcframeworks.sh +++ b/create-xcframeworks.sh @@ -5,7 +5,7 @@ rm -rf $ROOT for SDK in iphoneos iphonesimulator do xcodebuild archive \ - -workspace WordPressKit.xcworkspace \ + -project WordPressKit.xcodeproj \ -scheme WordPressKit \ -archivePath "$ROOT/WordPressKit-$SDK.xcarchive" \ -sdk $SDK \ From 561ae06b76d9c85fa2ff00be30023872dd8bc8e3 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 12 Jul 2024 19:45:07 -0400 Subject: [PATCH 13/97] Add SwiftLint back --- .../create-xcframeworks.sh | 2 +- Podfile | 36 +++++++++++++++++++ .../contents.xcworkspacedata | 7 ++++ .../xcshareddata/IDEWorkspaceChecks.plist | 8 +++++ 4 files changed, 52 insertions(+), 1 deletion(-) rename create-xcframeworks.sh => .buildkite/create-xcframeworks.sh (94%) create mode 100644 Podfile create mode 100644 WordPressKit.xcworkspace/contents.xcworkspacedata create mode 100644 WordPressKit.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/create-xcframeworks.sh b/.buildkite/create-xcframeworks.sh similarity index 94% rename from create-xcframeworks.sh rename to .buildkite/create-xcframeworks.sh index 97317259..27651d7f 100755 --- a/create-xcframeworks.sh +++ b/.buildkite/create-xcframeworks.sh @@ -5,7 +5,7 @@ rm -rf $ROOT for SDK in iphoneos iphonesimulator do xcodebuild archive \ - -project WordPressKit.xcodeproj \ + -workspace WordPressKit.xcworkspace \ -scheme WordPressKit \ -archivePath "$ROOT/WordPressKit-$SDK.xcarchive" \ -sdk $SDK \ diff --git a/Podfile b/Podfile new file mode 100644 index 00000000..5ca24888 --- /dev/null +++ b/Podfile @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +source 'https://cdn.cocoapods.org/' + +inhibit_all_warnings! +use_frameworks! + +APP_IOS_DEPLOYMENT_TARGET = Gem::Version.new('13.0') + +platform :ios, APP_IOS_DEPLOYMENT_TARGET + +def swiftlint_version + require 'yaml' + + YAML.load_file('.swiftlint.yml')['swiftlint_version'] +end + +abstract_target 'Tools' do + pod 'SwiftLint', swiftlint_version +end + +# Let Pods targets inherit deployment target from the app +post_install do |installer| + installer.pods_project.targets.each do |target| + target.build_configurations.each do |configuration| + ios_deployment_key = 'IPHONEOS_DEPLOYMENT_TARGET' + pod_ios_deployment_target = Gem::Version.new(configuration.build_settings[ios_deployment_key]) + configuration.build_settings.delete(ios_deployment_key) if pod_ios_deployment_target <= APP_IOS_DEPLOYMENT_TARGET + end + end + + yellow_marker = "\033[33m" + reset_marker = "\033[0m" + puts "#{yellow_marker}The abstract target warning below is expected. Feel free to ignore + it.#{reset_marker}" +end diff --git a/WordPressKit.xcworkspace/contents.xcworkspacedata b/WordPressKit.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..bbbd476d --- /dev/null +++ b/WordPressKit.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/WordPressKit.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/WordPressKit.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/WordPressKit.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From fa10ccd4bb10a81cf54657cb284a97a3c109e34b Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 12 Jul 2024 19:48:31 -0400 Subject: [PATCH 14/97] Add SwiftLint phase and fix violations --- .../WordPressComLanguageDatabase.swift | 5 ---- WordPressKit.xcodeproj/project.pbxproj | 23 +++++++++++++++++++ 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/Sources/WordPressShared/WordPressComLanguageDatabase.swift b/Sources/WordPressShared/WordPressComLanguageDatabase.swift index 21f8c4e8..d1239f17 100644 --- a/Sources/WordPressShared/WordPressComLanguageDatabase.swift +++ b/Sources/WordPressShared/WordPressComLanguageDatabase.swift @@ -128,8 +128,6 @@ class WordPressComLanguageDatabase: NSObject { return (Locale.current as NSLocale).displayName(forKey: NSLocale.Key.identifier, value: slug) ?? name } - - /// Designated initializer. Will fail if any of the required properties is missing /// init?(dict: [String: Any]) { @@ -147,7 +145,6 @@ class WordPressComLanguageDatabase: NSObject { slug = unwrappedSlug } - /// Given an array of raw languages, will return a parsed array. /// static func fromArray(_ array: [[String: Any]] ) -> [Language] { @@ -169,7 +166,6 @@ class WordPressComLanguageDatabase: NSObject { return NSLocale.preferredLanguages.first?.lowercased() ?? "en" }() - // MARK: - Private Constants fileprivate let filename = "Languages" @@ -180,7 +176,6 @@ class WordPressComLanguageDatabase: NSObject { "zh-hant": "zh-tw" ] - // MARK: - Private Nested Structures /// Keys used to parse the raw languages. diff --git a/WordPressKit.xcodeproj/project.pbxproj b/WordPressKit.xcodeproj/project.pbxproj index 8d2efb49..8b7c462c 100644 --- a/WordPressKit.xcodeproj/project.pbxproj +++ b/WordPressKit.xcodeproj/project.pbxproj @@ -2835,6 +2835,7 @@ 9368C7761EC5EF1B0092CE8E /* Sources */, 9368C7771EC5EF1B0092CE8E /* Frameworks */, 9368C7791EC5EF1B0092CE8E /* Resources */, + 0C2F2A2C2C41F82B000A153E /* SwiftLint */, ); buildRules = ( ); @@ -3256,6 +3257,28 @@ }; /* End PBXResourcesBuildPhase section */ +/* Begin PBXShellScriptBuildPhase section */ + 0C2F2A2C2C41F82B000A153E /* SwiftLint */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = SwiftLint; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "./Pods/SwiftLint/swiftlint lint\n"; + }; +/* End PBXShellScriptBuildPhase section */ + /* Begin PBXSourcesBuildPhase section */ 9368C7761EC5EF1B0092CE8E /* Sources */ = { isa = PBXSourcesBuildPhase; From 0cfeddca164530381034966f10e5c5af9e14db29 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 12 Jul 2024 19:56:30 -0400 Subject: [PATCH 15/97] Remove validate-podspec phase --- .buildkite/pipeline.yml | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml index e8fd0b65..10e07855 100644 --- a/.buildkite/pipeline.yml +++ b/.buildkite/pipeline.yml @@ -24,16 +24,6 @@ steps: env: *common_env plugins: *common_plugins - ################# - # Validate Podspec - ################# - - label: "🔬 Validate Podspec" - key: "validate" - command: | - validate_podspec --patch-cocoapods - env: *common_env - plugins: *common_plugins - ################# # Linters ################# From 25ccccd2f61786256a338ba4d72b967496a17e4a Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 12 Jul 2024 20:06:16 -0400 Subject: [PATCH 16/97] Fix Podfile --- Podfile | 1 + Podfile.lock | 16 ++++++++++++++++ .../contents.xcworkspacedata | 3 +++ 3 files changed, 20 insertions(+) create mode 100644 Podfile.lock diff --git a/Podfile b/Podfile index 5ca24888..c4ea2de3 100644 --- a/Podfile +++ b/Podfile @@ -8,6 +8,7 @@ use_frameworks! APP_IOS_DEPLOYMENT_TARGET = Gem::Version.new('13.0') platform :ios, APP_IOS_DEPLOYMENT_TARGET +workspace './WordPressKit.xcworkspace' def swiftlint_version require 'yaml' diff --git a/Podfile.lock b/Podfile.lock new file mode 100644 index 00000000..fd73c6a2 --- /dev/null +++ b/Podfile.lock @@ -0,0 +1,16 @@ +PODS: + - SwiftLint (0.54.0) + +DEPENDENCIES: + - SwiftLint (= 0.54.0) + +SPEC REPOS: + trunk: + - SwiftLint + +SPEC CHECKSUMS: + SwiftLint: c1de071d9d08c8aba837545f6254315bc900e211 + +PODFILE CHECKSUM: c0da9313733b88a1d938ba6a329dd46b895c7dea + +COCOAPODS: 1.15.2 diff --git a/WordPressKit.xcworkspace/contents.xcworkspacedata b/WordPressKit.xcworkspace/contents.xcworkspacedata index bbbd476d..c6817f81 100644 --- a/WordPressKit.xcworkspace/contents.xcworkspacedata +++ b/WordPressKit.xcworkspace/contents.xcworkspacedata @@ -4,4 +4,7 @@ + + From 01fe2726f66370db5d562175cf6623a5f8b76792 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 12 Jul 2024 20:14:18 -0400 Subject: [PATCH 17/97] Add changes made in wpios --- .../Services/MediaServiceRemoteXMLRPC.m | 58 +++++++++++++++---- 1 file changed, 46 insertions(+), 12 deletions(-) diff --git a/Sources/WordPressKit/Services/MediaServiceRemoteXMLRPC.m b/Sources/WordPressKit/Services/MediaServiceRemoteXMLRPC.m index ec04d042..5f01cf01 100644 --- a/Sources/WordPressKit/Services/MediaServiceRemoteXMLRPC.m +++ b/Sources/WordPressKit/Services/MediaServiceRemoteXMLRPC.m @@ -64,7 +64,7 @@ - (void)getMediaLibraryStartOffset:(NSUInteger)offset pageLoad(pageMedia); } NSUInteger newOffset = offset + pageSize; - [self getMediaLibraryStartOffset:newOffset media:resultMedia pageLoad:pageLoad success: success failure: failure]; + [self getMediaLibraryStartOffset:newOffset media:resultMedia pageLoad:pageLoad success: success failure: failure]; } failure:^(NSError *error, NSHTTPURLResponse *httpResponse) { if (failure) { @@ -104,7 +104,7 @@ - (NSURLCredential *)findCredentialForHost:(NSString *)host port:(NSInteger)port [[[NSURLCredentialStorage sharedCredentialStorage] allCredentials] enumerateKeysAndObjectsUsingBlock:^(NSURLProtectionSpace *ps, NSDictionary *dict, BOOL *stop) { [dict enumerateKeysAndObjectsUsingBlock:^(id key, NSURLCredential *credential, BOOL *stop) { if ([[ps host] isEqualToString:host] && [ps port] == port) - + { foundCredential = credential; *stop = YES; @@ -117,9 +117,9 @@ - (NSURLCredential *)findCredentialForHost:(NSString *)host port:(NSInteger)port return foundCredential; } -/** +/** Adds a basic auth header to a request if a credential is stored for that specific host. - + The credentials will only be added if a set of credentials for the request host are stored on the shared credential storage @param request The request to where the authentication information will be added. */ @@ -174,7 +174,7 @@ - (void)uploadMedia:(RemoteMedia *)media NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorBadServerResponse userInfo:@{NSLocalizedDescriptionKey: NSLocalizedString(@"The server returned an empty response. This usually means you need to increase the memory limit for your site.", @"")}]; if (failure) { failure(error); - } + } } else { localProgress.completedUnitCount=localProgress.totalUnitCount; RemoteMedia * remoteMedia = [self remoteMediaFromXMLRPCDictionary:response]; @@ -182,13 +182,13 @@ - (void)uploadMedia:(RemoteMedia *)media success(remoteMedia); } } - } failure:^(NSError *error, NSHTTPURLResponse *httpResponse) { + } failure:^(NSError *error, NSHTTPURLResponse *httpResponse) { if (failure) { failure(error); } }]; - + if (progress) { *progress = localProgress; } @@ -198,10 +198,44 @@ - (void)updateMedia:(RemoteMedia *)media success:(void (^)(RemoteMedia *remoteMedia))success failure:(void (^)(NSError *error))failure { - //HACK: Sergio Estevao: 2016-04-06 this option doens't exist on XML-RPC so we will always say that all was good - if (success) { - success(media); + NSParameterAssert([media.mediaID longLongValue] > 0); + + NSMutableDictionary *content = [NSMutableDictionary dictionary]; + + if (media.title != nil) { + content[@"post_title"] = media.title; + } + + if (media.caption != nil) { + content[@"post_excerpt"] = media.caption; } + + if (media.descriptionText != nil) { + content[@"post_content"] = media.descriptionText; + } + + NSArray *extraDefaults = @[media.mediaID]; + NSArray *parameters = [self XMLRPCArgumentsWithExtraDefaults:extraDefaults andExtra:content]; + + [self.api callMethod:@"wp.editPost" + parameters:parameters + success:^(id responseObject, NSHTTPURLResponse *httpResponse) { + BOOL updated = [responseObject boolValue]; + if (updated) { + if (success) { + success(media); + } + } else { + if (failure) { + NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorUnknown userInfo:nil]; + failure(error); + } + } + } failure:^(NSError *error, NSHTTPURLResponse *httpResponse) { + if (failure) { + failure(error); + } + }]; } - (void)deleteMedia:(RemoteMedia *)media @@ -285,11 +319,11 @@ - (RemoteMedia *)remoteMediaFromXMLRPCDictionary:(NSDictionary*)xmlRPC link = [xmlRPC stringForKeyPath:@"link"]; } remoteMedia.file = [link lastPathComponent] ?: [[xmlRPC objectForKeyPath:@"file"] lastPathComponent]; - + if ([xmlRPC stringForKeyPath:@"metadata.sizes.large.file"] != nil) { remoteMedia.largeURL = [NSURL URLWithString: [NSString stringWithFormat:@"%@%@", remoteMedia.url.URLByDeletingLastPathComponent, [xmlRPC stringForKeyPath:@"metadata.sizes.large.file"]]]; } - + if ([xmlRPC stringForKeyPath:@"metadata.sizes.medium.file"] != nil) { remoteMedia.mediumURL = [NSURL URLWithString: [NSString stringWithFormat:@"%@%@", remoteMedia.url.URLByDeletingLastPathComponent, [xmlRPC stringForKeyPath:@"metadata.sizes.medium.file"]]]; } From eee1e016b517e7f447d71281efcec7a9480b34fc Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 12 Jul 2024 20:22:57 -0400 Subject: [PATCH 18/97] Add Package.swift --- Package.swift | 46 +++++++--------------------------------------- 1 file changed, 7 insertions(+), 39 deletions(-) diff --git a/Package.swift b/Package.swift index 027d1c01..80186894 100644 --- a/Package.swift +++ b/Package.swift @@ -1,50 +1,18 @@ -// swift-tools-version: 5.9 +// swift-tools-version: 5.10 import PackageDescription let package = Package( name: "WordPressKit", - platforms: [.iOS(.v13)], + platforms: [.iOS(.v15)], products: [ - .library(name: "APIInterface", targets: ["APIInterface"]), - .library(name: "CoreAPI", targets: ["CoreAPI"]), - ], - dependencies: [ - // .package(url: "https://github.com/wordpress-mobile/WordPress-iOS-Shared.git", from: "2.3.1"), - // See https://github.com/wordpress-mobile/WordPress-iOS-Shared/pull/354 - .package(url: "https://github.com/wordpress-mobile/WordPress-iOS-Shared.git", branch: "mokagio/swiftlint-read-as-dependency"), - .package(url: "https://github.com/wordpress-mobile/wpxmlrpc", from: "0.10.0"), - // Test dependencies - .package(url: "https://github.com/AliSoftware/OHHTTPStubs", from: "9.1.0"), - .package(url: "https://github.com/Alamofire/Alamofire", from: "5.8.1"), + .library(name: "WordPressKit", targets: ["WordPressKit"]), ], targets: [ - .target(name: "APIInterface"), - .target( - name: "CoreAPI", - dependencies: [ - .target(name: "APIInterface"), - .product( - name: "WordPressShared", - package: "WordPress-iOS-Shared", - // Constrain to iOS only to avoid having to explicitly set a macOS version because of this library's requirements. - condition: .when(platforms: [.iOS]) - ), - "wpxmlrpc" - ] - ), - .testTarget( - name: "CoreAPITests", - dependencies: [ - .target(name: "CoreAPI"), - .product(name: "OHHTTPStubs", package: "OHHTTPStubs"), - .product(name: "OHHTTPStubsSwift", package: "OHHTTPStubs"), - "Alamofire", - ], - path: "Tests/CoreAPITests", - resources: [ - .process("Stubs") // Relative to path - ] + .binaryTarget( + name: "WordPressKit", + url: "https://github.com/user-attachments/files/16200320/WordPressKit.zip", + checksum: "fa2ddc1fedcc225beb23d23168043bd78bbd12d43e187cc0dd772aef8d81ee20" ), ] ) From 0583ccc9f1f6b748bab6a9242bbf585351d18caa Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 12 Jul 2024 21:14:12 -0400 Subject: [PATCH 19/97] Update some of the public APIs --- Package.swift | 4 ++-- Sources/CoreAPI/HTTPRequestBuilder.swift | 4 ++-- Sources/CoreAPI/WordPressAPIError.swift | 2 +- Sources/CoreAPI/WordPressComRestApi.swift | 4 ++-- Sources/CoreAPI/WordPressOrgXMLRPCApi.swift | 4 ++++ .../WordPressKit/Models/AccountSettings.swift | 2 +- Sources/WordPressKit/Models/Activity.swift | 4 ++-- .../Models/Atomic/AtomicLogs.swift | 2 +- .../Models/Blaze/BlazeCampaign.swift | 2 +- .../WordPressKit/Models/JetpackBackup.swift | 11 +++++++++ .../Models/Plugins/PluginState.swift | 2 +- .../Models/RemoteNotificationSettings.swift | 2 +- .../StatsTagsAndCategoriesInsight.swift | 2 +- .../StatsSummaryTimeIntervalData.swift | 4 ++-- Sources/WordPressKit/Models/WPTimeZone.swift | 5 ++++ .../Services/AnnouncementServiceRemote.swift | 24 +++++++++++++++++-- .../Services/AutomatedTransferService.swift | 4 ++-- .../Services/Plans/PlanServiceRemote.swift | 4 ++-- .../Services/PostServiceRemoteExtended.swift | 2 +- .../QR Login/QRLoginServiceRemote.swift | 2 +- .../ReaderServiceDeliveryFrequency.swift | 2 +- .../Services/StatsServiceRemoteV2.swift | 2 +- ...rdPressComServiceRemote+SiteSegments.swift | 2 +- .../Utility/ZendeskMetadata.swift | 5 ++++ WordPressKit.xcodeproj/project.pbxproj | 2 ++ 25 files changed, 75 insertions(+), 28 deletions(-) diff --git a/Package.swift b/Package.swift index 80186894..814c33dc 100644 --- a/Package.swift +++ b/Package.swift @@ -11,8 +11,8 @@ let package = Package( targets: [ .binaryTarget( name: "WordPressKit", - url: "https://github.com/user-attachments/files/16200320/WordPressKit.zip", - checksum: "fa2ddc1fedcc225beb23d23168043bd78bbd12d43e187cc0dd772aef8d81ee20" + url: "https://github.com/user-attachments/files/16200443/WordPressKit.zip", + checksum: "09fde69ac4ca044a02ed52daa478c025c66fcfbf6cb5b64af2ab7959fc403508" ), ] ) diff --git a/Sources/CoreAPI/HTTPRequestBuilder.swift b/Sources/CoreAPI/HTTPRequestBuilder.swift index 506b8010..c230b7ef 100644 --- a/Sources/CoreAPI/HTTPRequestBuilder.swift +++ b/Sources/CoreAPI/HTTPRequestBuilder.swift @@ -5,8 +5,8 @@ import Foundation /// /// 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/CoreAPI/WordPressAPIError.swift b/Sources/CoreAPI/WordPressAPIError.swift index a4680b20..cd8493f0 100644 --- a/Sources/CoreAPI/WordPressAPIError.swift +++ b/Sources/CoreAPI/WordPressAPIError.swift @@ -1,6 +1,6 @@ import Foundation -public enum WordPressAPIError: Error where EndpointError: LocalizedError { +@frozen public enum WordPressAPIError: Error where EndpointError: LocalizedError { static var unknownErrorMessage: String { NSLocalizedString( "wordpress-api.error.unknown", diff --git a/Sources/CoreAPI/WordPressComRestApi.swift b/Sources/CoreAPI/WordPressComRestApi.swift index f5937ba6..8b96fb32 100644 --- a/Sources/CoreAPI/WordPressComRestApi.swift +++ b/Sources/CoreAPI/WordPressComRestApi.swift @@ -362,7 +362,7 @@ open class WordPressComRestApi: NSObject { return configuration } - func perform( + open func perform( _ method: HTTPRequestBuilder.Method, URLString: String, parameters: [String: AnyObject]? = nil, @@ -373,7 +373,7 @@ open class WordPressComRestApi: NSObject { } } - func perform( + open func perform( _ method: HTTPRequestBuilder.Method, URLString: String, parameters: [String: AnyObject]? = nil, diff --git a/Sources/CoreAPI/WordPressOrgXMLRPCApi.swift b/Sources/CoreAPI/WordPressOrgXMLRPCApi.swift index 58c57633..a997efd1 100644 --- a/Sources/CoreAPI/WordPressOrgXMLRPCApi.swift +++ b/Sources/CoreAPI/WordPressOrgXMLRPCApi.swift @@ -28,6 +28,10 @@ open class WordPressOrgXMLRPCApi: NSObject { /// @objc public static let minimumSupportedVersion = "4.0" + @objc public static var errorDomain: String { + wpxmlrpc.WPXMLRPCFaultErrorDomain + } + private lazy var urlSession: URLSession = makeSession(configuration: .default) private lazy var uploadURLSession: URLSession = { backgroundUploads diff --git a/Sources/WordPressKit/Models/AccountSettings.swift b/Sources/WordPressKit/Models/AccountSettings.swift index 7cf0ab20..91993fa4 100644 --- a/Sources/WordPressKit/Models/AccountSettings.swift +++ b/Sources/WordPressKit/Models/AccountSettings.swift @@ -53,7 +53,7 @@ public struct AccountSettings { } } -public enum AccountSettingsChange { +@frozen public enum AccountSettingsChange { case firstName(String) case lastName(String) case displayName(String) diff --git a/Sources/WordPressKit/Models/Activity.swift b/Sources/WordPressKit/Models/Activity.swift index cd6afb3a..66bb996b 100644 --- a/Sources/WordPressKit/Models/Activity.swift +++ b/Sources/WordPressKit/Models/Activity.swift @@ -182,7 +182,7 @@ public class ActivityGroup { public let name: String public let count: Int - init(_ groupKey: String, dictionary: [String: AnyObject]) throws { + public init(_ groupKey: String, dictionary: [String: AnyObject]) throws { guard let groupName = dictionary["name"] as? String else { throw Error.missingName } @@ -293,7 +293,7 @@ public class RestoreStatus { } public extension RestoreStatus { - enum Status: String { + @frozen enum Status: String { case queued case finished case running diff --git a/Sources/WordPressKit/Models/Atomic/AtomicLogs.swift b/Sources/WordPressKit/Models/Atomic/AtomicLogs.swift index bc04ca68..c0fcb7e3 100644 --- a/Sources/WordPressKit/Models/Atomic/AtomicLogs.swift +++ b/Sources/WordPressKit/Models/Atomic/AtomicLogs.swift @@ -9,7 +9,7 @@ public final class AtomicErrorLogEntry: Decodable { public let line: Int? public let timestamp: Date? - public enum Severity: String { + @frozen public enum Severity: String { case user = "User" case warning = "Warning" case deprecated = "Deprecated" diff --git a/Sources/WordPressKit/Models/Blaze/BlazeCampaign.swift b/Sources/WordPressKit/Models/Blaze/BlazeCampaign.swift index be303fc4..5ab9af98 100644 --- a/Sources/WordPressKit/Models/Blaze/BlazeCampaign.swift +++ b/Sources/WordPressKit/Models/Blaze/BlazeCampaign.swift @@ -44,7 +44,7 @@ public final class BlazeCampaign: Codable { case creativeHTML = "creativeHtml" } - public enum Status: String, Codable { + @frozen public enum Status: String, Codable { case scheduled case created case rejected diff --git a/Sources/WordPressKit/Models/JetpackBackup.swift b/Sources/WordPressKit/Models/JetpackBackup.swift index 2b8b0832..6bd56dc2 100644 --- a/Sources/WordPressKit/Models/JetpackBackup.swift +++ b/Sources/WordPressKit/Models/JetpackBackup.swift @@ -26,4 +26,15 @@ public struct JetpackBackup: Decodable { case url case validUntil } + + public init(backupPoint: Date, downloadID: Int, rewindID: String, startedAt: Date, progress: Int?, downloadCount: Int?, url: String?, validUntil: Date?) { + self.backupPoint = backupPoint + self.downloadID = downloadID + self.rewindID = rewindID + self.startedAt = startedAt + self.progress = progress + self.downloadCount = downloadCount + self.url = url + self.validUntil = validUntil + } } diff --git a/Sources/WordPressKit/Models/Plugins/PluginState.swift b/Sources/WordPressKit/Models/Plugins/PluginState.swift index 62f0dbea..8123998d 100644 --- a/Sources/WordPressKit/Models/Plugins/PluginState.swift +++ b/Sources/WordPressKit/Models/Plugins/PluginState.swift @@ -1,7 +1,7 @@ import Foundation public struct PluginState: Equatable, Codable { - public enum UpdateState: Equatable, Codable { + @frozen public enum UpdateState: Equatable, Codable { public static func ==(lhs: PluginState.UpdateState, rhs: PluginState.UpdateState) -> Bool { switch (lhs, rhs) { case (.updated, .updated): diff --git a/Sources/WordPressKit/Models/RemoteNotificationSettings.swift b/Sources/WordPressKit/Models/RemoteNotificationSettings.swift index 1c8cba2e..bb9f6632 100644 --- a/Sources/WordPressKit/Models/RemoteNotificationSettings.swift +++ b/Sources/WordPressKit/Models/RemoteNotificationSettings.swift @@ -21,7 +21,7 @@ open class RemoteNotificationSettings { /// Represents a communication channel that may post notifications to the user. /// - public enum Channel: Equatable { + @frozen public enum Channel: Equatable { case blog(blogId: Int) case other case wordPressCom diff --git a/Sources/WordPressKit/Models/Stats/Insights/StatsTagsAndCategoriesInsight.swift b/Sources/WordPressKit/Models/Stats/Insights/StatsTagsAndCategoriesInsight.swift index 8daaad19..4af5e2a4 100644 --- a/Sources/WordPressKit/Models/Stats/Insights/StatsTagsAndCategoriesInsight.swift +++ b/Sources/WordPressKit/Models/Stats/Insights/StatsTagsAndCategoriesInsight.swift @@ -13,7 +13,7 @@ extension StatsTagsAndCategoriesInsight: StatsInsightData { } public struct StatsTagAndCategory: Codable { - public enum Kind: String, Codable { + @frozen public enum Kind: String, Codable { case tag case category case folder diff --git a/Sources/WordPressKit/Models/Stats/Time Interval/StatsSummaryTimeIntervalData.swift b/Sources/WordPressKit/Models/Stats/Time Interval/StatsSummaryTimeIntervalData.swift index d24447fc..acefd4b7 100644 --- a/Sources/WordPressKit/Models/Stats/Time Interval/StatsSummaryTimeIntervalData.swift +++ b/Sources/WordPressKit/Models/Stats/Time Interval/StatsSummaryTimeIntervalData.swift @@ -1,11 +1,11 @@ -public enum StatsPeriodUnit: Int { +@frozen public enum StatsPeriodUnit: Int { case day case week case month case year } -public enum StatsSummaryType: Int { +@frozen public enum StatsSummaryType: Int { case views case visitors case likes diff --git a/Sources/WordPressKit/Models/WPTimeZone.swift b/Sources/WordPressKit/Models/WPTimeZone.swift index 8974acef..9654d2ad 100644 --- a/Sources/WordPressKit/Models/WPTimeZone.swift +++ b/Sources/WordPressKit/Models/WPTimeZone.swift @@ -30,6 +30,11 @@ public struct NamedTimeZone: WPTimeZone { public let label: String public let value: String + public init(label: String, value: String) { + self.label = label + self.value = value + } + public var gmtOffset: Float? { return nil } diff --git a/Sources/WordPressKit/Services/AnnouncementServiceRemote.swift b/Sources/WordPressKit/Services/AnnouncementServiceRemote.swift index 343680b3..fe5e24f2 100644 --- a/Sources/WordPressKit/Services/AnnouncementServiceRemote.swift +++ b/Sources/WordPressKit/Services/AnnouncementServiceRemote.swift @@ -1,9 +1,9 @@ import Foundation /// Retrieves feature announcements from the related endpoint -public class AnnouncementServiceRemote: ServiceRemoteWordPressComREST { +open class AnnouncementServiceRemote: ServiceRemoteWordPressComREST { - public func getAnnouncements(appId: String, + open func getAnnouncements(appId: String, appVersion: String, locale: String, completion: @escaping (Result<[Announcement], Error>) -> Void) { @@ -86,6 +86,18 @@ public struct Announcement: Codable { public let isLocalized: Bool public let responseLocale: String public let features: [Feature] + + public init(appVersionName: String, minimumAppVersion: String, maximumAppVersion: String, appVersionTargets: [String], detailsUrl: String, announcementVersion: String, isLocalized: Bool, responseLocale: String, features: [Feature]) { + self.appVersionName = appVersionName + self.minimumAppVersion = minimumAppVersion + self.maximumAppVersion = maximumAppVersion + self.appVersionTargets = appVersionTargets + self.detailsUrl = detailsUrl + self.announcementVersion = announcementVersion + self.isLocalized = isLocalized + self.responseLocale = responseLocale + self.features = features + } } public struct Feature: Codable { @@ -94,6 +106,14 @@ public struct Feature: Codable { public let icons: [FeatureIcon]? public let iconUrl: String public let iconBase64: String? + + public init(title: String, subtitle: String, icons: [FeatureIcon]?, iconUrl: String, iconBase64: String?) { + self.title = title + self.subtitle = subtitle + self.icons = icons + self.iconUrl = iconUrl + self.iconBase64 = iconBase64 + } } public struct FeatureIcon: Codable { diff --git a/Sources/WordPressKit/Services/AutomatedTransferService.swift b/Sources/WordPressKit/Services/AutomatedTransferService.swift index 168783e8..13b87ad6 100644 --- a/Sources/WordPressKit/Services/AutomatedTransferService.swift +++ b/Sources/WordPressKit/Services/AutomatedTransferService.swift @@ -3,11 +3,11 @@ import Foundation /// Class encapsualting all requests related to performing Automated Transfer operations. public class AutomatedTransferService: ServiceRemoteWordPressComREST { - public enum ResponseError: Error { + @frozen public enum ResponseError: Error { case decodingFailure } - public enum AutomatedTransferEligibilityError: Error { + @frozen public enum AutomatedTransferEligibilityError: Error { case unverifiedEmail case excessiveDiskSpaceUsage case noBusinessPlan diff --git a/Sources/WordPressKit/Services/Plans/PlanServiceRemote.swift b/Sources/WordPressKit/Services/Plans/PlanServiceRemote.swift index cada673c..b31f8e21 100644 --- a/Sources/WordPressKit/Services/Plans/PlanServiceRemote.swift +++ b/Sources/WordPressKit/Services/Plans/PlanServiceRemote.swift @@ -1,6 +1,6 @@ import Foundation -public class PlanServiceRemote: ServiceRemoteWordPressComREST { +open class PlanServiceRemote: ServiceRemoteWordPressComREST { public typealias AvailablePlans = (plans: [RemoteWpcomPlan], groups: [RemotePlanGroup], features: [RemotePlanFeature]) typealias EndpointResponse = [String: AnyObject] @@ -191,7 +191,7 @@ public class PlanServiceRemote: ServiceRemoteWordPressComREST { } /// Retrieves Zendesk meta data: plan and Jetpack addons, if available - public func getZendeskMetadata(siteID: Int, completion: @escaping (Result) -> Void) { + open func getZendeskMetadata(siteID: Int, completion: @escaping (Result) -> Void) { let endpoint = "me/sites" let path = self.path(forEndpoint: endpoint, withVersion: ._1_1) let parameters = ["fields": "ID, zendesk_site_meta"] as [String: AnyObject] diff --git a/Sources/WordPressKit/Services/PostServiceRemoteExtended.swift b/Sources/WordPressKit/Services/PostServiceRemoteExtended.swift index f5a6f1cb..700c1b33 100644 --- a/Sources/WordPressKit/Services/PostServiceRemoteExtended.swift +++ b/Sources/WordPressKit/Services/PostServiceRemoteExtended.swift @@ -23,7 +23,7 @@ public protocol PostServiceRemoteExtended: PostServiceRemote { func deletePost(withID postID: Int) async throws } -public enum PostServiceRemoteError: Error { +@frozen public enum PostServiceRemoteError: Error { /// 409 (Conflict) case conflict /// 404 (Not Found) diff --git a/Sources/WordPressKit/Services/QR Login/QRLoginServiceRemote.swift b/Sources/WordPressKit/Services/QR Login/QRLoginServiceRemote.swift index a84aa6ba..cad2fe17 100644 --- a/Sources/WordPressKit/Services/QR Login/QRLoginServiceRemote.swift +++ b/Sources/WordPressKit/Services/QR Login/QRLoginServiceRemote.swift @@ -46,7 +46,7 @@ open class QRLoginServiceRemote: ServiceRemoteWordPressComREST { } } -public enum QRLoginError { +@frozen public enum QRLoginError { case invalidData case expired diff --git a/Sources/WordPressKit/Services/ReaderServiceDeliveryFrequency.swift b/Sources/WordPressKit/Services/ReaderServiceDeliveryFrequency.swift index 96090898..b7d060a9 100644 --- a/Sources/WordPressKit/Services/ReaderServiceDeliveryFrequency.swift +++ b/Sources/WordPressKit/Services/ReaderServiceDeliveryFrequency.swift @@ -5,7 +5,7 @@ import Foundation /// - daily: daily frequency /// - instantly: instantly frequency /// - weekly: weekly frequency -public enum ReaderServiceDeliveryFrequency: String { +@frozen public enum ReaderServiceDeliveryFrequency: String { case daily case instantly case weekly diff --git a/Sources/WordPressKit/Services/StatsServiceRemoteV2.swift b/Sources/WordPressKit/Services/StatsServiceRemoteV2.swift index 6cf675a6..02b9ce94 100644 --- a/Sources/WordPressKit/Services/StatsServiceRemoteV2.swift +++ b/Sources/WordPressKit/Services/StatsServiceRemoteV2.swift @@ -99,7 +99,7 @@ open class StatsServiceRemoteV2: ServiceRemoteWordPressComREST { /// e.g. if you want data spanning 11-17 Feb 2019, you should pass in a period of `.week` and an /// ending date of `Feb 17 2019`. /// - limit: Limit of how many objects you want returned for your query. Default is `10`. `0` means no limit. - public func getData(for period: StatsPeriodUnit, + open func getData(for period: StatsPeriodUnit, unit: StatsPeriodUnit? = nil, endingOn: Date, limit: Int = 10, diff --git a/Sources/WordPressKit/Services/WordPressComServiceRemote+SiteSegments.swift b/Sources/WordPressKit/Services/WordPressComServiceRemote+SiteSegments.swift index 179d0a21..63763e0e 100644 --- a/Sources/WordPressKit/Services/WordPressComServiceRemote+SiteSegments.swift +++ b/Sources/WordPressKit/Services/WordPressComServiceRemote+SiteSegments.swift @@ -79,7 +79,7 @@ public enum SiteSegmentsError: Error { /// - success: the site segments request succeeded with the accompanying result. /// - failure: the site segments request failed due to the accompanying error. /// -public enum SiteSegmentsResult { +@frozen public enum SiteSegmentsResult { case success([SiteSegment]) case failure(SiteSegmentsError) } diff --git a/Sources/WordPressKit/Utility/ZendeskMetadata.swift b/Sources/WordPressKit/Utility/ZendeskMetadata.swift index 4090f0d4..3b772a01 100644 --- a/Sources/WordPressKit/Utility/ZendeskMetadata.swift +++ b/Sources/WordPressKit/Utility/ZendeskMetadata.swift @@ -20,6 +20,11 @@ public struct ZendeskMetadata: Decodable { case plan = "plan" case jetpackAddons = "addon" } + + public init(plan: String, jetpackAddons: [String]) { + self.plan = plan + self.jetpackAddons = jetpackAddons + } } /// Errors generated by the metadata decoding process diff --git a/WordPressKit.xcodeproj/project.pbxproj b/WordPressKit.xcodeproj/project.pbxproj index 8b7c462c..23851528 100644 --- a/WordPressKit.xcodeproj/project.pbxproj +++ b/WordPressKit.xcodeproj/project.pbxproj @@ -798,6 +798,7 @@ 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 = ""; }; + 0C6183C62C420A3700289E73 /* Package.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = ""; }; 0C674E2F2BF3A91300F3B3D4 /* JetpackAIServiceRemote.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JetpackAIServiceRemote.swift; sourceTree = ""; }; 0C938A052C416789009BA7B2 /* Secret.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Secret.swift; sourceTree = ""; }; 0C938A072C4167BB009BA7B2 /* NSString+XMLExtensions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+XMLExtensions.h"; sourceTree = ""; }; @@ -2317,6 +2318,7 @@ 9368C7711EC5EF1B0092CE8E = { isa = PBXGroup; children = ( + 0C6183C62C420A3700289E73 /* Package.swift */, 3FE2E9432BB11413002CA2E1 /* Sources */, 3FE2E9442BB11592002CA2E1 /* Tests */, FFE247CD20CB1245002DF3A2 /* LICENSE */, From 80a7cd20cfaa2e1862cee6ec48cadbab47044783 Mon Sep 17 00:00:00 2001 From: kean Date: Tue, 6 Aug 2024 15:54:52 -0400 Subject: [PATCH 20/97] Add is_wpcom_staging_site --- Sources/WordPressKit/Models/RemoteBlogOptionsHelper.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Sources/WordPressKit/Models/RemoteBlogOptionsHelper.swift b/Sources/WordPressKit/Models/RemoteBlogOptionsHelper.swift index aac09a7a..a048db6d 100644 --- a/Sources/WordPressKit/Models/RemoteBlogOptionsHelper.swift +++ b/Sources/WordPressKit/Models/RemoteBlogOptionsHelper.swift @@ -28,6 +28,7 @@ import Foundation "blog_public", "max_upload_size", "is_wpcom_atomic", + "is_wpcom_staging_site", "is_wpforteams_site", "show_on_front", "page_on_front", From 67c6e6895acc201c72f152330dd04ff3ab51d286 Mon Sep 17 00:00:00 2001 From: kean Date: Tue, 6 Aug 2024 15:56:24 -0400 Subject: [PATCH 21/97] Add missing @frozen --- .../Stats/Time Interval/StatsTopAuthorsTimeIntervalData.swift | 2 +- .../Services/AccountServiceRemoteREST+SocialService.swift | 2 +- .../Services/WordPressComServiceRemote+SiteCreation.swift | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Sources/WordPressKit/Models/Stats/Time Interval/StatsTopAuthorsTimeIntervalData.swift b/Sources/WordPressKit/Models/Stats/Time Interval/StatsTopAuthorsTimeIntervalData.swift index e5e592f8..63b90b31 100644 --- a/Sources/WordPressKit/Models/Stats/Time Interval/StatsTopAuthorsTimeIntervalData.swift +++ b/Sources/WordPressKit/Models/Stats/Time Interval/StatsTopAuthorsTimeIntervalData.swift @@ -32,7 +32,7 @@ public struct StatsTopAuthor { public struct StatsTopPost { - public enum Kind { + @frozen public enum Kind { case unknown case post case page diff --git a/Sources/WordPressKit/Services/AccountServiceRemoteREST+SocialService.swift b/Sources/WordPressKit/Services/AccountServiceRemoteREST+SocialService.swift index 02432a1f..c487ba4a 100644 --- a/Sources/WordPressKit/Services/AccountServiceRemoteREST+SocialService.swift +++ b/Sources/WordPressKit/Services/AccountServiceRemoteREST+SocialService.swift @@ -1,6 +1,6 @@ import Foundation -public enum SocialServiceName: String { +@frozen public enum SocialServiceName: String { case google case apple } diff --git a/Sources/WordPressKit/Services/WordPressComServiceRemote+SiteCreation.swift b/Sources/WordPressKit/Services/WordPressComServiceRemote+SiteCreation.swift index c65f80e5..b2fb6614 100644 --- a/Sources/WordPressKit/Services/WordPressComServiceRemote+SiteCreation.swift +++ b/Sources/WordPressKit/Services/WordPressComServiceRemote+SiteCreation.swift @@ -169,7 +169,7 @@ public enum SiteCreationError: Error { /// - success: the site creation request succeeded with the accompanying result. /// - failure: the site creation request failed due to the accompanying error. /// -public enum SiteCreationResult { +@frozen public enum SiteCreationResult { case success(SiteCreationResponse) case failure(SiteCreationError) } From c3eeb90e7a4f3664f85ff53f1fef009cda17d5b6 Mon Sep 17 00:00:00 2001 From: kean Date: Wed, 7 Aug 2024 12:11:11 -0400 Subject: [PATCH 22/97] Update Package.swift --- Package.swift | 4 ++-- Sources/WordPressKit/Models/RemoteBlogOptionsHelper.swift | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Package.swift b/Package.swift index 814c33dc..cc9d2340 100644 --- a/Package.swift +++ b/Package.swift @@ -11,8 +11,8 @@ let package = Package( targets: [ .binaryTarget( name: "WordPressKit", - url: "https://github.com/user-attachments/files/16200443/WordPressKit.zip", - checksum: "09fde69ac4ca044a02ed52daa478c025c66fcfbf6cb5b64af2ab7959fc403508" + url: "https://github.com/user-attachments/files/16531883/WordPressKit.zip", + checksum: "ca916824c64a6061814a69a37bc9a6560aafcc35559983e945fdfa5c3bbcc23d" ), ] ) diff --git a/Sources/WordPressKit/Models/RemoteBlogOptionsHelper.swift b/Sources/WordPressKit/Models/RemoteBlogOptionsHelper.swift index a048db6d..a5eca541 100644 --- a/Sources/WordPressKit/Models/RemoteBlogOptionsHelper.swift +++ b/Sources/WordPressKit/Models/RemoteBlogOptionsHelper.swift @@ -8,6 +8,9 @@ import Foundation if response.number(forKey: "jetpack")?.boolValue == true { options["jetpack_client_id"] = response.number(forKey: "ID") } + if response.number(forKey: "is_wpcom_staging_site")?.boolValue == true { + options["is_wpcom_staging_site"] = true + } if response["options"] != nil { options["post_thumbnail"] = response.value(forKeyPath: "options.featured_images_enabled") From 05af184b808fe906d7f8697ca47ecd23af6ff981 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 18 Oct 2024 09:01:08 -0400 Subject: [PATCH 23/97] Update Reader APIs --- Package.swift | 4 ++-- Sources/WordPressKit/Models/RemoteReaderPost.m | 5 ++++- .../Services/ReaderPostServiceRemote+Cards.swift | 6 ++++-- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/Package.swift b/Package.swift index cc9d2340..1dac9141 100644 --- a/Package.swift +++ b/Package.swift @@ -11,8 +11,8 @@ let package = Package( targets: [ .binaryTarget( name: "WordPressKit", - url: "https://github.com/user-attachments/files/16531883/WordPressKit.zip", - checksum: "ca916824c64a6061814a69a37bc9a6560aafcc35559983e945fdfa5c3bbcc23d" + url: "https://github.com/user-attachments/files/17435861/WordPressKit.zip", + checksum: "af7239442da8470a91ef5ab923fd91222bb3c0ea345b18f581bfafd63f0dd6b6" ), ] ) diff --git a/Sources/WordPressKit/Models/RemoteReaderPost.m b/Sources/WordPressKit/Models/RemoteReaderPost.m index 889a903c..d5cb92b7 100644 --- a/Sources/WordPressKit/Models/RemoteReaderPost.m +++ b/Sources/WordPressKit/Models/RemoteReaderPost.m @@ -97,7 +97,10 @@ - (instancetype)initWithDictionary:(NSDictionary *)dict; self.authorDisplayName = [[self stringOrEmptyString:[authorDict stringForKey:PostRESTKeyName]] wpkit_stringByDecodingXMLCharacters]; // Typically the author's given name self.authorEmail = [self authorEmailFromAuthorDictionary:authorDict]; self.authorURL = [self stringOrEmptyString:[authorDict stringForKey:PostRESTKeyURL]]; - self.siteIconURL = [self stringOrEmptyString:[dict stringForKeyPath:@"meta.data.site.icon.img"]]; + self.siteIconURL = [self stringOrEmptyString:[dict stringForKeyPath:@"site_icon.img"]]; + if (self.siteIconURL.length == 0) { + self.siteIconURL = [self stringOrEmptyString:[dict stringForKeyPath:@"meta.data.site.icon.img"]]; + } self.blogName = [self siteNameFromPostDictionary:dict]; self.blogDescription = [self siteDescriptionFromPostDictionary:dict]; self.blogURL = [self siteURLFromPostDictionary:dict]; diff --git a/Sources/WordPressKit/Services/ReaderPostServiceRemote+Cards.swift b/Sources/WordPressKit/Services/ReaderPostServiceRemote+Cards.swift index 36ae18df..7b1b1a40 100644 --- a/Sources/WordPressKit/Services/ReaderPostServiceRemote+Cards.swift +++ b/Sources/WordPressKit/Services/ReaderPostServiceRemote+Cards.swift @@ -46,20 +46,22 @@ extension ReaderPostServiceRemote { /// - Topics you may like /// - Blogs you may like and so on /// + /// - Parameter stream: The name of the stream. By default, `discover`. /// - Parameter topics: an array of String representing the topics /// - Parameter page: a String that represents a page handle /// - Parameter sortingOption: a ReaderSortingOption that represents a sorting option /// - Parameter count: the number of cards to fetch. Warning: This also changes the number of objects returned for recommended sites/tags. /// - Parameter success: Called when the request succeeds and the data returned is valid /// - Parameter failure: Called if the request fails for any reason, or the response data is invalid - public func fetchStreamCards(for topics: [String], + public func fetchStreamCards(stream: String = "discover", + for topics: [String], page: String? = nil, sortingOption: ReaderSortingOption = .noSorting, refreshCount: Int? = nil, count: Int? = nil, success: @escaping ([RemoteReaderCard], String?) -> Void, failure: @escaping (Error) -> Void) { - let path = "read/streams/discover" + let path = "read/streams/\(stream)" guard let requestUrl = cardsEndpoint(with: path, topics: topics, page: page, From a5dfe35cd92e4df8bdd971edd162ecf02b7d0a29 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 18 Oct 2024 09:09:58 -0400 Subject: [PATCH 24/97] Add ReaderStream enum --- Package.swift | 4 ++-- .../Services/ReaderPostServiceRemote+Cards.swift | 11 ++++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/Package.swift b/Package.swift index 1dac9141..801d4a09 100644 --- a/Package.swift +++ b/Package.swift @@ -11,8 +11,8 @@ let package = Package( targets: [ .binaryTarget( name: "WordPressKit", - url: "https://github.com/user-attachments/files/17435861/WordPressKit.zip", - checksum: "af7239442da8470a91ef5ab923fd91222bb3c0ea345b18f581bfafd63f0dd6b6" + url: "https://github.com/user-attachments/files/17435956/WordPressKit.zip", + checksum: "b3babe54d211d862e485ab3a742080dc9f2a5f04e2a6fa1d675545b0d00a795e" ), ] ) diff --git a/Sources/WordPressKit/Services/ReaderPostServiceRemote+Cards.swift b/Sources/WordPressKit/Services/ReaderPostServiceRemote+Cards.swift index 7b1b1a40..6795c9b7 100644 --- a/Sources/WordPressKit/Services/ReaderPostServiceRemote+Cards.swift +++ b/Sources/WordPressKit/Services/ReaderPostServiceRemote+Cards.swift @@ -11,6 +11,11 @@ public enum ReaderSortingOption: String, CaseIterable { } } +public enum ReaderStream: String { + case discover = "discover" + case firstPosts = "first-posts" +} + extension ReaderPostServiceRemote { /// Returns a collection of RemoteReaderCard using the tags API /// a Reader Card can represent an item for the reader feed, such as @@ -46,14 +51,14 @@ extension ReaderPostServiceRemote { /// - Topics you may like /// - Blogs you may like and so on /// - /// - Parameter stream: The name of the stream. By default, `discover`. + /// - Parameter stream: The name of the stream. By default, `.discover`. /// - Parameter topics: an array of String representing the topics /// - Parameter page: a String that represents a page handle /// - Parameter sortingOption: a ReaderSortingOption that represents a sorting option /// - Parameter count: the number of cards to fetch. Warning: This also changes the number of objects returned for recommended sites/tags. /// - Parameter success: Called when the request succeeds and the data returned is valid /// - Parameter failure: Called if the request fails for any reason, or the response data is invalid - public func fetchStreamCards(stream: String = "discover", + public func fetchStreamCards(stream: ReaderStream = .discover, for topics: [String], page: String? = nil, sortingOption: ReaderSortingOption = .noSorting, @@ -61,7 +66,7 @@ extension ReaderPostServiceRemote { count: Int? = nil, success: @escaping ([RemoteReaderCard], String?) -> Void, failure: @escaping (Error) -> Void) { - let path = "read/streams/\(stream)" + let path = "read/streams/\(stream.rawValue)" guard let requestUrl = cardsEndpoint(with: path, topics: topics, page: page, From 7a3624f3e896b8d61763a37d5ca393e768244122 Mon Sep 17 00:00:00 2001 From: kean Date: Thu, 19 Dec 2024 15:54:31 -0500 Subject: [PATCH 25/97] Add StatsEmailsSummaryData.SortField.postDate --- Package.swift | 4 ++-- .../Models/Stats/Emails/StatsEmailsSummaryData.swift | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Package.swift b/Package.swift index 801d4a09..1c40239b 100644 --- a/Package.swift +++ b/Package.swift @@ -11,8 +11,8 @@ let package = Package( targets: [ .binaryTarget( name: "WordPressKit", - url: "https://github.com/user-attachments/files/17435956/WordPressKit.zip", - checksum: "b3babe54d211d862e485ab3a742080dc9f2a5f04e2a6fa1d675545b0d00a795e" + url: "https://github.com/user-attachments/files/18203178/WordPressKit.zip", + checksum: "ceb5ac66cda7b207f123319d6c04c338b90b7657344e7f395f86d36ff9e61f4a" ), ] ) diff --git a/Sources/WordPressKit/Models/Stats/Emails/StatsEmailsSummaryData.swift b/Sources/WordPressKit/Models/Stats/Emails/StatsEmailsSummaryData.swift index 55267e0c..4ed6d59f 100644 --- a/Sources/WordPressKit/Models/Stats/Emails/StatsEmailsSummaryData.swift +++ b/Sources/WordPressKit/Models/Stats/Emails/StatsEmailsSummaryData.swift @@ -84,6 +84,7 @@ extension StatsEmailsSummaryData { public enum SortField: String { case opens = "opens" case postId = "post_id" + case postDate = "post_date" } public enum SortOrder: String { From 87e2a0902e84e03afdc29bb5b52b3a3d6a1e14d9 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 20 Dec 2024 05:38:19 -0500 Subject: [PATCH 26/97] Remove automatically resolved featured images --- Package.swift | 4 ++-- Sources/WordPressKit/Models/RemoteReaderPost.m | 10 ---------- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/Package.swift b/Package.swift index 1c40239b..89a26215 100644 --- a/Package.swift +++ b/Package.swift @@ -11,8 +11,8 @@ let package = Package( targets: [ .binaryTarget( name: "WordPressKit", - url: "https://github.com/user-attachments/files/18203178/WordPressKit.zip", - checksum: "ceb5ac66cda7b207f123319d6c04c338b90b7657344e7f395f86d36ff9e61f4a" + url: "https://github.com/user-attachments/files/18209758/WordPressKit.zip", + checksum: "2c9fa7ed59864c01c8af7dc0b5dd8cbc26558799487fad3ab9e128cfbd8dae64" ), ] ) diff --git a/Sources/WordPressKit/Models/RemoteReaderPost.m b/Sources/WordPressKit/Models/RemoteReaderPost.m index d5cb92b7..061c73b5 100644 --- a/Sources/WordPressKit/Models/RemoteReaderPost.m +++ b/Sources/WordPressKit/Models/RemoteReaderPost.m @@ -494,16 +494,6 @@ - (NSString *)featuredImageFromPostDictionary:(NSDictionary *)dict featuredImage = [self userSpecifiedFeaturedImageFromPostDictionary:dict]; } - // If that's not present look for an image in featured media - if ([featuredImage length] == 0) { - featuredImage = [self featuredMediaImageFromPostDictionary:dict]; - } - - // As a last resource lets look for a suitable image in the post content - if ([featuredImage length] == 0) { - featuredImage = [self suitableImageFromPostContent:dict]; - } - featuredImage = [self sanitizeFeaturedImageString:featuredImage]; return featuredImage; From 10097d5399b51ac0c8e54784019f3c810d269826 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 10 Jan 2025 10:39:01 -0500 Subject: [PATCH 27/97] Remove lazy-laod --- Package.swift | 4 ++-- .../Models/RemoteBlogJetpackModulesSettings.swift | 9 +-------- .../Services/BlogJetpackSettingsServiceRemote.swift | 7 ++----- 3 files changed, 5 insertions(+), 15 deletions(-) diff --git a/Package.swift b/Package.swift index 89a26215..55324dd4 100644 --- a/Package.swift +++ b/Package.swift @@ -11,8 +11,8 @@ let package = Package( targets: [ .binaryTarget( name: "WordPressKit", - url: "https://github.com/user-attachments/files/18209758/WordPressKit.zip", - checksum: "2c9fa7ed59864c01c8af7dc0b5dd8cbc26558799487fad3ab9e128cfbd8dae64" + url: "https://github.com/user-attachments/files/18379301/WordPressKit.zip", + checksum: "afd882de3a6a672c32c6cc7e6e1c1e68ff4e1366e7613af4eab59415ed7abb59" ), ] ) diff --git a/Sources/WordPressKit/Models/RemoteBlogJetpackModulesSettings.swift b/Sources/WordPressKit/Models/RemoteBlogJetpackModulesSettings.swift index 0c3ce7da..d1af811a 100644 --- a/Sources/WordPressKit/Models/RemoteBlogJetpackModulesSettings.swift +++ b/Sources/WordPressKit/Models/RemoteBlogJetpackModulesSettings.swift @@ -3,18 +3,11 @@ import Foundation /// This struct encapsulates the *remote* Jetpack modules settings available for a Blog entity /// public struct RemoteBlogJetpackModulesSettings { - - /// Indicates whether the Jetpack site lazy loads images. - /// - public let lazyLoadImages: Bool - /// Indicates whether the Jetpack site serves images from our server. /// public let serveImagesFromOurServers: Bool - public init(lazyLoadImages: Bool, serveImagesFromOurServers: Bool) { - self.lazyLoadImages = lazyLoadImages + public init(serveImagesFromOurServers: Bool) { self.serveImagesFromOurServers = serveImagesFromOurServers } - } diff --git a/Sources/WordPressKit/Services/BlogJetpackSettingsServiceRemote.swift b/Sources/WordPressKit/Services/BlogJetpackSettingsServiceRemote.swift index d12342a2..b18c84c7 100644 --- a/Sources/WordPressKit/Services/BlogJetpackSettingsServiceRemote.swift +++ b/Sources/WordPressKit/Services/BlogJetpackSettingsServiceRemote.swift @@ -200,13 +200,11 @@ private extension BlogJetpackSettingsServiceRemote { $0[key] = $1 } - guard let lazyLoadImagesValue = dictionary[Keys.lazyLoadImages]?[ModuleOptionKeys.active] as? Bool, - let serveImagesFromOurServersValue = dictionary[Keys.serveImagesFromOurServers]?[ModuleOptionKeys.active] as? Bool else { + guard let serveImagesFromOurServersValue = dictionary[Keys.serveImagesFromOurServers]?[ModuleOptionKeys.active] as? Bool else { throw ResponseError.decodingFailure } - return RemoteBlogJetpackModulesSettings(lazyLoadImages: lazyLoadImagesValue, - serveImagesFromOurServers: serveImagesFromOurServersValue) + return RemoteBlogJetpackModulesSettings(serveImagesFromOurServers: serveImagesFromOurServersValue) } func dictionaryFromJetpackSettings(_ settings: RemoteBlogJetpackSettings) -> [String: Any] { @@ -248,7 +246,6 @@ public extension BlogJetpackSettingsServiceRemote { static let monitorPushNotifications = "wp_note_notifications" // RemoteBlogJetpackModuleSettings keys - public static let lazyLoadImages = "lazy-images" public static let serveImagesFromOurServers = "photon" } From fe83ee7b72598d8b7c3282af1e39bb208f4a4202 Mon Sep 17 00:00:00 2001 From: Tony Li Date: Tue, 28 Jan 2025 21:02:04 +1300 Subject: [PATCH 28/97] Add an argument to use ephemeral URLSession to send WP.com API requests --- Sources/CoreAPI/WordPressComRestApi.swift | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/Sources/CoreAPI/WordPressComRestApi.swift b/Sources/CoreAPI/WordPressComRestApi.swift index 8b96fb32..17b476ef 100644 --- a/Sources/CoreAPI/WordPressComRestApi.swift +++ b/Sources/CoreAPI/WordPressComRestApi.swift @@ -103,6 +103,8 @@ open class WordPressComRestApi: NSObject { private var invalidTokenHandler: (() -> Void)? + private var useEphemeralSession: Bool + /** Configure whether or not the user's preferred language locale should be appended. Defaults to true. */ @@ -139,7 +141,8 @@ open class WordPressComRestApi: NSObject { backgroundSessionIdentifier: String = WordPressComRestApi.defaultBackgroundSessionIdentifier, sharedContainerIdentifier: String? = nil, localeKey: String = WordPressComRestApi.LocaleKeyDefault, - baseURL: URL = WordPressComRestApi.apiBaseURL) { + baseURL: URL = WordPressComRestApi.apiBaseURL, + useEphemeralSession: Bool = false) { self.oAuthToken = oAuthToken self.userAgent = userAgent self.backgroundUploads = backgroundUploads @@ -147,6 +150,7 @@ open class WordPressComRestApi: NSObject { self.sharedContainerIdentifier = sharedContainerIdentifier self.localeKey = localeKey self.baseURL = baseURL + self.useEphemeralSession = useEphemeralSession super.init() } @@ -347,7 +351,14 @@ open class WordPressComRestApi: NSObject { }() private func sessionConfiguration(background: Bool) -> URLSessionConfiguration { - let configuration = background ? URLSessionConfiguration.background(withIdentifier: self.backgroundSessionIdentifier) : URLSessionConfiguration.default + let configuration: URLSessionConfiguration + if background { + configuration = .background(withIdentifier: self.backgroundSessionIdentifier) + } else if useEphemeralSession { + configuration = .ephemeral + } else { + configuration = .default + } var additionalHeaders: [String: AnyObject] = [:] if let oAuthToken = self.oAuthToken { From 253b6954f9676a3b10910c24f14231130cad2284 Mon Sep 17 00:00:00 2001 From: Tony Li Date: Tue, 28 Jan 2025 21:11:25 +1300 Subject: [PATCH 29/97] Update binary target --- Package.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Package.swift b/Package.swift index 55324dd4..b7b5df79 100644 --- a/Package.swift +++ b/Package.swift @@ -11,8 +11,8 @@ let package = Package( targets: [ .binaryTarget( name: "WordPressKit", - url: "https://github.com/user-attachments/files/18379301/WordPressKit.zip", - checksum: "afd882de3a6a672c32c6cc7e6e1c1e68ff4e1366e7613af4eab59415ed7abb59" + url: "https://github.com/user-attachments/files/18570063/WordPressKit.zip", + checksum: "fc25d3065e80af713dac970db7ed89ff37e4cc98afc98b6a2ecf7b47b2ddd0c1" ), ] ) From d46b5be685c9921e235d3135d03a7f51fb5fb4c1 Mon Sep 17 00:00:00 2001 From: kean Date: Thu, 20 Feb 2025 10:47:49 -0500 Subject: [PATCH 30/97] Add RemoteComment as a reponse object in CommentServiceRemote --- Package.swift | 4 ++-- .../Services/CommentServiceRemoteREST.h | 2 +- .../Services/CommentServiceRemoteREST.m | 19 ++++++++++--------- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/Package.swift b/Package.swift index b7b5df79..4dcb9f30 100644 --- a/Package.swift +++ b/Package.swift @@ -11,8 +11,8 @@ let package = Package( targets: [ .binaryTarget( name: "WordPressKit", - url: "https://github.com/user-attachments/files/18570063/WordPressKit.zip", - checksum: "fc25d3065e80af713dac970db7ed89ff37e4cc98afc98b6a2ecf7b47b2ddd0c1" + url: "https://github.com/user-attachments/files/18891163/WordPressKit.zip", + checksum: "a768cf1578321fbda9bcbd025f00697773f9dc978a31b7ae9174c310a20596f8" ), ] ) diff --git a/Sources/WordPressKit/Services/CommentServiceRemoteREST.h b/Sources/WordPressKit/Services/CommentServiceRemoteREST.h index e4323aad..4089461a 100644 --- a/Sources/WordPressKit/Services/CommentServiceRemoteREST.h +++ b/Sources/WordPressKit/Services/CommentServiceRemoteREST.h @@ -30,7 +30,7 @@ */ - (void)updateCommentWithID:(NSNumber * _Nonnull)commentID content:(NSString * _Nonnull)content - success:(void (^ _Nullable)(void))success + success:(void (^ _Nullable)(RemoteComment * _Nullable comment))success failure:(void (^ _Nullable)(NSError * _Nullable error))failure; /** diff --git a/Sources/WordPressKit/Services/CommentServiceRemoteREST.m b/Sources/WordPressKit/Services/CommentServiceRemoteREST.m index 4b0f3761..3a610c20 100644 --- a/Sources/WordPressKit/Services/CommentServiceRemoteREST.m +++ b/Sources/WordPressKit/Services/CommentServiceRemoteREST.m @@ -246,7 +246,7 @@ - (void)syncHierarchicalCommentsForPost:(NSNumber *)postID - (void)updateCommentWithID:(NSNumber *)commentID content:(NSString *)content - success:(void (^)(void))success + success:(void (^)(RemoteComment *comment))success failure:(void (^)(NSError *error))failure { NSString *path = [NSString stringWithFormat:@"sites/%@/comments/%@", self.siteID, commentID]; @@ -260,14 +260,15 @@ - (void)updateCommentWithID:(NSNumber *)commentID [self.wordPressComRESTAPI post:requestUrl parameters:parameters success:^(id responseObject, NSHTTPURLResponse *httpResponse) { - if (success) { - success(); - } - } failure:^(NSError *error, NSHTTPURLResponse *httpResponse) { - if (failure) { - failure(error); - } - }]; + RemoteComment *comment = [self remoteCommentFromJSONDictionary:responseObject]; + if (success) { + success(comment); + } + } failure:^(NSError *error, NSHTTPURLResponse *httpResponse) { + if (failure) { + failure(error); + } + }]; } - (void)replyToPostWithID:(NSNumber *)postID From 2846106755b17ab44d69ea1df1af65e308eab044 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 28 Feb 2025 17:59:05 -0500 Subject: [PATCH 31/97] Add autoSuggestedFeaturedImage --- Sources/WordPressKit/Models/RemoteReaderPost.h | 1 + Sources/WordPressKit/Models/RemoteReaderPost.m | 1 + 2 files changed, 2 insertions(+) diff --git a/Sources/WordPressKit/Models/RemoteReaderPost.h b/Sources/WordPressKit/Models/RemoteReaderPost.h index f25b51a7..a7ac757e 100644 --- a/Sources/WordPressKit/Models/RemoteReaderPost.h +++ b/Sources/WordPressKit/Models/RemoteReaderPost.h @@ -17,6 +17,7 @@ @property (nonatomic, strong) NSNumber *commentCount; @property (nonatomic) BOOL commentsOpen; @property (nonatomic, strong) NSString *featuredImage; +@property (nonatomic, strong) NSString *autoSuggestedFeaturedImage; @property (nonatomic, strong) NSNumber *feedID; @property (nonatomic, strong) NSNumber *feedItemID; @property (nonatomic, strong) NSString *globalID; diff --git a/Sources/WordPressKit/Models/RemoteReaderPost.m b/Sources/WordPressKit/Models/RemoteReaderPost.m index 061c73b5..c184a046 100644 --- a/Sources/WordPressKit/Models/RemoteReaderPost.m +++ b/Sources/WordPressKit/Models/RemoteReaderPost.m @@ -109,6 +109,7 @@ - (instancetype)initWithDictionary:(NSDictionary *)dict; self.content = [self postContentFromPostDictionary:dict]; self.date_created_gmt = [self stringOrEmptyString:[dict stringForKey:PostRESTKeyDate]]; self.featuredImage = [self featuredImageFromPostDictionary:dict]; + self.autoSuggestedFeaturedImage = [self featuredMediaImageFromPostDictionary:dict]; self.feedID = [dict numberForKey:PostRESTKeyFeedID]; self.feedItemID = [dict numberForKey:PostRESTKeyFeedItemID]; self.globalID = [self stringOrEmptyString:[dict stringForKey:PostRESTKeyGlobalID]]; From 4500041eb1df4efc6b8ce73290f5675cab256994 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 28 Feb 2025 18:13:41 -0500 Subject: [PATCH 32/97] Udpate package --- Package.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Package.swift b/Package.swift index 4dcb9f30..cdd6fa37 100644 --- a/Package.swift +++ b/Package.swift @@ -11,8 +11,8 @@ let package = Package( targets: [ .binaryTarget( name: "WordPressKit", - url: "https://github.com/user-attachments/files/18891163/WordPressKit.zip", - checksum: "a768cf1578321fbda9bcbd025f00697773f9dc978a31b7ae9174c310a20596f8" + url: "https://github.com/user-attachments/files/19034102/WordPressKit.zip", + checksum: "1d845ec9b6b22ae82f309dc7909333b952ca28a523b8e483230f4d3884ef0a0f" ), ] ) From 30563e2b5e3fc1b009467a92b8282cbff30f79be Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 28 Feb 2025 18:30:59 -0500 Subject: [PATCH 33/97] Add suitableImageFromPostContent --- Package.swift | 4 ++-- Sources/WordPressKit/Models/RemoteReaderPost.h | 1 + Sources/WordPressKit/Models/RemoteReaderPost.m | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Package.swift b/Package.swift index cdd6fa37..965f2427 100644 --- a/Package.swift +++ b/Package.swift @@ -11,8 +11,8 @@ let package = Package( targets: [ .binaryTarget( name: "WordPressKit", - url: "https://github.com/user-attachments/files/19034102/WordPressKit.zip", - checksum: "1d845ec9b6b22ae82f309dc7909333b952ca28a523b8e483230f4d3884ef0a0f" + url: "https://github.com/user-attachments/files/19034191/WordPressKit.zip", + checksum: "34f108cba86b5e4334d1c9af79946dbb8b665e270bdd14bc8f7bc0ba7a898583" ), ] ) diff --git a/Sources/WordPressKit/Models/RemoteReaderPost.h b/Sources/WordPressKit/Models/RemoteReaderPost.h index a7ac757e..fa623cdc 100644 --- a/Sources/WordPressKit/Models/RemoteReaderPost.h +++ b/Sources/WordPressKit/Models/RemoteReaderPost.h @@ -18,6 +18,7 @@ @property (nonatomic) BOOL commentsOpen; @property (nonatomic, strong) NSString *featuredImage; @property (nonatomic, strong) NSString *autoSuggestedFeaturedImage; +@property (nonatomic, strong) NSString *suitableImageFromPostContent; @property (nonatomic, strong) NSNumber *feedID; @property (nonatomic, strong) NSNumber *feedItemID; @property (nonatomic, strong) NSString *globalID; diff --git a/Sources/WordPressKit/Models/RemoteReaderPost.m b/Sources/WordPressKit/Models/RemoteReaderPost.m index c184a046..ebefeb08 100644 --- a/Sources/WordPressKit/Models/RemoteReaderPost.m +++ b/Sources/WordPressKit/Models/RemoteReaderPost.m @@ -109,7 +109,8 @@ - (instancetype)initWithDictionary:(NSDictionary *)dict; self.content = [self postContentFromPostDictionary:dict]; self.date_created_gmt = [self stringOrEmptyString:[dict stringForKey:PostRESTKeyDate]]; self.featuredImage = [self featuredImageFromPostDictionary:dict]; - self.autoSuggestedFeaturedImage = [self featuredMediaImageFromPostDictionary:dict]; + self.autoSuggestedFeaturedImage = [self sanitizeFeaturedImageString:[self featuredMediaImageFromPostDictionary:dict]]; + self.suitableImageFromPostContent = [self sanitizeFeaturedImageString:[self suitableImageFromPostContent:dict]]; self.feedID = [dict numberForKey:PostRESTKeyFeedID]; self.feedItemID = [dict numberForKey:PostRESTKeyFeedItemID]; self.globalID = [self stringOrEmptyString:[dict stringForKey:PostRESTKeyGlobalID]]; From bad387c51b0a2f1a39954a9901c5b2a8687ef82d Mon Sep 17 00:00:00 2001 From: kean Date: Mon, 3 Mar 2025 08:24:26 -0500 Subject: [PATCH 34/97] Update tests --- Tests/WordPressKitTests/Tests/RemoteReaderPostTests.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/WordPressKitTests/Tests/RemoteReaderPostTests.m b/Tests/WordPressKitTests/Tests/RemoteReaderPostTests.m index c5aedf61..565020a1 100644 --- a/Tests/WordPressKitTests/Tests/RemoteReaderPostTests.m +++ b/Tests/WordPressKitTests/Tests/RemoteReaderPostTests.m @@ -209,7 +209,7 @@ - (void)testFeaturedImageFromDictionary { uri, uri, uri] }; imagePath = [remoteReaderPost featuredImageFromPostDictionary:dict]; - XCTAssertTrue([uri isEqualToString:imagePath], @"Failed to retrieve the image uri from the post content."); + XCTAssertTrue(imagePath.length == 0, @"No image should be retrieved from the content"); dict = [self editorialDictionaryWithKey:@"image" value:uri]; imagePath = [remoteReaderPost featuredImageFromPostDictionary:dict]; From 976f035480ff56ac2b652d56964721027d5cc517 Mon Sep 17 00:00:00 2001 From: Tony Li Date: Tue, 18 Mar 2025 14:13:23 +1300 Subject: [PATCH 35/97] Return visible sites only by default --- Sources/WordPressKit/Services/AccountServiceRemoteREST.m | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Sources/WordPressKit/Services/AccountServiceRemoteREST.m b/Sources/WordPressKit/Services/AccountServiceRemoteREST.m index a8290c2b..b394760c 100644 --- a/Sources/WordPressKit/Services/AccountServiceRemoteREST.m +++ b/Sources/WordPressKit/Services/AccountServiceRemoteREST.m @@ -354,6 +354,11 @@ - (void)getBlogsWithParameters:(NSDictionary *)parameters { NSString *requestUrl = [self pathForEndpoint:@"me/sites" withVersion:WordPressComRESTAPIVersion_1_2]; + if (parameters[@"site_visibility"] == nil) { + NSMutableDictionary *another = [parameters mutableCopy]; + another[@"site_visibility"] = @"visible"; + parameters = another; + } [self.wordPressComRESTAPI get:requestUrl parameters:parameters success:^(id responseObject, NSHTTPURLResponse *httpResponse) { From baf2f408162e882cb7e14d50932546efa79f6a0b Mon Sep 17 00:00:00 2001 From: Tony Li Date: Tue, 18 Mar 2025 22:32:33 +1300 Subject: [PATCH 36/97] Update Package.swift --- Package.swift | 4 ++-- Sources/WordPressKit/Models/RemoteBlog.swift | 3 +++ .../Services/AccountServiceRemoteREST.m | 13 ++++++------- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/Package.swift b/Package.swift index 965f2427..7a1c94c5 100644 --- a/Package.swift +++ b/Package.swift @@ -11,8 +11,8 @@ let package = Package( targets: [ .binaryTarget( name: "WordPressKit", - url: "https://github.com/user-attachments/files/19034191/WordPressKit.zip", - checksum: "34f108cba86b5e4334d1c9af79946dbb8b665e270bdd14bc8f7bc0ba7a898583" + url: "https://github.com/user-attachments/files/19315257/WordPressKit.zip", + checksum: "1b4ba5cef01a64e98ffdc02a5c8ac92f550f234222bfb6abf11b4b4df94435bc" ), ] ) diff --git a/Sources/WordPressKit/Models/RemoteBlog.swift b/Sources/WordPressKit/Models/RemoteBlog.swift index 99bea7dc..795c9394 100644 --- a/Sources/WordPressKit/Models/RemoteBlog.swift +++ b/Sources/WordPressKit/Models/RemoteBlog.swift @@ -58,6 +58,8 @@ import Foundation /// Blog's total disk quota space used. public var quotaSpaceUsed: NSNumber? + public var isDeleted: Bool + /// Parses details from a JSON dictionary, as returned by the WordPress.com REST API. @objc(initWithJSONDictionary:) public init(jsonDictionary json: NSDictionary) { @@ -79,6 +81,7 @@ import Foundation self.planActiveFeatures = (json.array(forKeyPath: "plan.features.active") as? [String]) ?? [] self.quotaSpaceAllowed = json.number(forKeyPath: "quota.space_allowed") self.quotaSpaceUsed = json.number(forKeyPath: "quota.space_used") + self.isDeleted = json.number(forKey: "is_deleted")?.boolValue == true } } diff --git a/Sources/WordPressKit/Services/AccountServiceRemoteREST.m b/Sources/WordPressKit/Services/AccountServiceRemoteREST.m index b394760c..ab1041a7 100644 --- a/Sources/WordPressKit/Services/AccountServiceRemoteREST.m +++ b/Sources/WordPressKit/Services/AccountServiceRemoteREST.m @@ -354,11 +354,6 @@ - (void)getBlogsWithParameters:(NSDictionary *)parameters { NSString *requestUrl = [self pathForEndpoint:@"me/sites" withVersion:WordPressComRESTAPIVersion_1_2]; - if (parameters[@"site_visibility"] == nil) { - NSMutableDictionary *another = [parameters mutableCopy]; - another[@"site_visibility"] = @"visible"; - parameters = another; - } [self.wordPressComRESTAPI get:requestUrl parameters:parameters success:^(id responseObject, NSHTTPURLResponse *httpResponse) { @@ -390,10 +385,14 @@ - (RemoteUser *)remoteUserFromDictionary:(NSDictionary *)dictionary - (NSArray *)remoteBlogsFromJSONArray:(NSArray *)jsonBlogs { NSArray *blogs = jsonBlogs; - return [blogs wpkit_map:^id(NSDictionary *jsonBlog) { + return [[blogs wpkit_map:^id(NSDictionary *jsonBlog) { return [[RemoteBlog alloc] initWithJSONDictionary:jsonBlog]; + }] wpkit_filter:^BOOL(RemoteBlog *blog) { + // Exclude deleted sites from query result, since the app does not handle deleted sites properly. + // I tried to use query arguments `site_visibility=visible` and `site_activity=active`, but neither excludes + // deleted sites. + return !blog.isDeleted; }]; - return blogs; } @end From 074fc43d7b404acbe0b481c6d6e3d9e46b162025 Mon Sep 17 00:00:00 2001 From: Paolo Musolino Date: Tue, 18 Mar 2025 12:47:32 +0100 Subject: [PATCH 37/97] Add search parameter to `getWPThemesPage` method --- Sources/WordPressKit/Services/ThemeServiceRemote.h | 2 ++ Sources/WordPressKit/Services/ThemeServiceRemote.m | 14 ++++++++++---- .../Tests/ThemeServiceRemoteTests.m | 1 + 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/Sources/WordPressKit/Services/ThemeServiceRemote.h b/Sources/WordPressKit/Services/ThemeServiceRemote.h index 3ee51c4a..3235a327 100644 --- a/Sources/WordPressKit/Services/ThemeServiceRemote.h +++ b/Sources/WordPressKit/Services/ThemeServiceRemote.h @@ -60,6 +60,7 @@ typedef void(^ThemeServiceRemoteFailureBlock)(NSError *error); * * @param freeOnly Only fetch free themes, if false all WP themes will be returned * @param page Results page to return. + * @param search Search term to filter themes. Can be nil or empty string. * @param success The success handler. Can be nil. * @param failure The failure handler. Can be nil. * @@ -67,6 +68,7 @@ typedef void(^ThemeServiceRemoteFailureBlock)(NSError *error); */ - (NSProgress *)getWPThemesPage:(NSInteger)page freeOnly:(BOOL)freeOnly + search:(NSString *)search success:(ThemeServiceRemoteThemesRequestSuccessBlock)success failure:(ThemeServiceRemoteFailureBlock)failure; diff --git a/Sources/WordPressKit/Services/ThemeServiceRemote.m b/Sources/WordPressKit/Services/ThemeServiceRemote.m index 97d6e60e..7d7511c8 100644 --- a/Sources/WordPressKit/Services/ThemeServiceRemote.m +++ b/Sources/WordPressKit/Services/ThemeServiceRemote.m @@ -99,6 +99,7 @@ - (NSProgress *)getThemeId:(NSString*)themeId - (NSProgress *)getWPThemesPage:(NSInteger)page freeOnly:(BOOL)freeOnly + search:(NSString *)search success:(ThemeServiceRemoteThemesRequestSuccessBlock)success failure:(ThemeServiceRemoteFailureBlock)failure { @@ -107,10 +108,15 @@ - (NSProgress *)getWPThemesPage:(NSInteger)page NSString *requestUrl = [self pathForEndpoint:@"themes" withVersion:WordPressComRESTAPIVersion_1_2]; - NSDictionary *parameters = @{ThemeRequestTierKey: freeOnly ? ThemeRequestTierFreeValue : ThemeRequestTierAllValue, - ThemeRequestNumberKey: @(ThemeRequestNumberValue), - ThemeRequestPageKey: @(page), - }; + NSMutableDictionary *parameters = [@{ + ThemeRequestTierKey: freeOnly ? ThemeRequestTierFreeValue : ThemeRequestTierAllValue, + ThemeRequestNumberKey: @(ThemeRequestNumberValue), + ThemeRequestPageKey: @(page) + } mutableCopy]; + + if (search && search.length > 0) { + parameters[@"search"] = search; + } return [self getThemesWithRequestUrl:requestUrl page:page diff --git a/Tests/WordPressKitTests/Tests/ThemeServiceRemoteTests.m b/Tests/WordPressKitTests/Tests/ThemeServiceRemoteTests.m index e0a6ac7f..435c57e3 100644 --- a/Tests/WordPressKitTests/Tests/ThemeServiceRemoteTests.m +++ b/Tests/WordPressKitTests/Tests/ThemeServiceRemoteTests.m @@ -225,6 +225,7 @@ - (void)testThatGetThemesWorks XCTAssertNoThrow([service getWPThemesPage:1 freeOnly:NO + search:nil success:successBlock failure:nil]); } From a5a49e7bc1b3d15a30ae81254b2ccc504e77e848 Mon Sep 17 00:00:00 2001 From: Paolo Musolino Date: Tue, 18 Mar 2025 13:01:51 +0100 Subject: [PATCH 38/97] update: Package.swift --- Package.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Package.swift b/Package.swift index 965f2427..d913a0b0 100644 --- a/Package.swift +++ b/Package.swift @@ -11,8 +11,8 @@ let package = Package( targets: [ .binaryTarget( name: "WordPressKit", - url: "https://github.com/user-attachments/files/19034191/WordPressKit.zip", - checksum: "34f108cba86b5e4334d1c9af79946dbb8b665e270bdd14bc8f7bc0ba7a898583" + url: "https://github.com/user-attachments/files/19318154/WordPressKit.zip", + checksum: "769f4ec0c4e3712844af318962af7ffb417c8723c61688c913c381e6ac57e8b6" ), ] ) From affb54f7448c3f3d1ede99a37f12dd5d48f8e830 Mon Sep 17 00:00:00 2001 From: Paolo Musolino Date: Tue, 18 Mar 2025 14:19:37 +0100 Subject: [PATCH 39/97] Revert "update: Package.swift" This reverts commit a5a49e7bc1b3d15a30ae81254b2ccc504e77e848. --- Package.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Package.swift b/Package.swift index d913a0b0..965f2427 100644 --- a/Package.swift +++ b/Package.swift @@ -11,8 +11,8 @@ let package = Package( targets: [ .binaryTarget( name: "WordPressKit", - url: "https://github.com/user-attachments/files/19318154/WordPressKit.zip", - checksum: "769f4ec0c4e3712844af318962af7ffb417c8723c61688c913c381e6ac57e8b6" + url: "https://github.com/user-attachments/files/19034191/WordPressKit.zip", + checksum: "34f108cba86b5e4334d1c9af79946dbb8b665e270bdd14bc8f7bc0ba7a898583" ), ] ) From 244b6c474adb012ac9211a9872dfdb90f1890f64 Mon Sep 17 00:00:00 2001 From: Paolo Musolino Date: Tue, 18 Mar 2025 14:20:06 +0100 Subject: [PATCH 40/97] Revert "Add search parameter to `getWPThemesPage` method" This reverts commit 074fc43d7b404acbe0b481c6d6e3d9e46b162025. --- Sources/WordPressKit/Services/ThemeServiceRemote.h | 2 -- Sources/WordPressKit/Services/ThemeServiceRemote.m | 14 ++++---------- .../Tests/ThemeServiceRemoteTests.m | 1 - 3 files changed, 4 insertions(+), 13 deletions(-) diff --git a/Sources/WordPressKit/Services/ThemeServiceRemote.h b/Sources/WordPressKit/Services/ThemeServiceRemote.h index 3235a327..3ee51c4a 100644 --- a/Sources/WordPressKit/Services/ThemeServiceRemote.h +++ b/Sources/WordPressKit/Services/ThemeServiceRemote.h @@ -60,7 +60,6 @@ typedef void(^ThemeServiceRemoteFailureBlock)(NSError *error); * * @param freeOnly Only fetch free themes, if false all WP themes will be returned * @param page Results page to return. - * @param search Search term to filter themes. Can be nil or empty string. * @param success The success handler. Can be nil. * @param failure The failure handler. Can be nil. * @@ -68,7 +67,6 @@ typedef void(^ThemeServiceRemoteFailureBlock)(NSError *error); */ - (NSProgress *)getWPThemesPage:(NSInteger)page freeOnly:(BOOL)freeOnly - search:(NSString *)search success:(ThemeServiceRemoteThemesRequestSuccessBlock)success failure:(ThemeServiceRemoteFailureBlock)failure; diff --git a/Sources/WordPressKit/Services/ThemeServiceRemote.m b/Sources/WordPressKit/Services/ThemeServiceRemote.m index 7d7511c8..97d6e60e 100644 --- a/Sources/WordPressKit/Services/ThemeServiceRemote.m +++ b/Sources/WordPressKit/Services/ThemeServiceRemote.m @@ -99,7 +99,6 @@ - (NSProgress *)getThemeId:(NSString*)themeId - (NSProgress *)getWPThemesPage:(NSInteger)page freeOnly:(BOOL)freeOnly - search:(NSString *)search success:(ThemeServiceRemoteThemesRequestSuccessBlock)success failure:(ThemeServiceRemoteFailureBlock)failure { @@ -108,15 +107,10 @@ - (NSProgress *)getWPThemesPage:(NSInteger)page NSString *requestUrl = [self pathForEndpoint:@"themes" withVersion:WordPressComRESTAPIVersion_1_2]; - NSMutableDictionary *parameters = [@{ - ThemeRequestTierKey: freeOnly ? ThemeRequestTierFreeValue : ThemeRequestTierAllValue, - ThemeRequestNumberKey: @(ThemeRequestNumberValue), - ThemeRequestPageKey: @(page) - } mutableCopy]; - - if (search && search.length > 0) { - parameters[@"search"] = search; - } + NSDictionary *parameters = @{ThemeRequestTierKey: freeOnly ? ThemeRequestTierFreeValue : ThemeRequestTierAllValue, + ThemeRequestNumberKey: @(ThemeRequestNumberValue), + ThemeRequestPageKey: @(page), + }; return [self getThemesWithRequestUrl:requestUrl page:page diff --git a/Tests/WordPressKitTests/Tests/ThemeServiceRemoteTests.m b/Tests/WordPressKitTests/Tests/ThemeServiceRemoteTests.m index 435c57e3..e0a6ac7f 100644 --- a/Tests/WordPressKitTests/Tests/ThemeServiceRemoteTests.m +++ b/Tests/WordPressKitTests/Tests/ThemeServiceRemoteTests.m @@ -225,7 +225,6 @@ - (void)testThatGetThemesWorks XCTAssertNoThrow([service getWPThemesPage:1 freeOnly:NO - search:nil success:successBlock failure:nil]); } From 842c9dc2e6140891b96154ea386720b96fb09aa5 Mon Sep 17 00:00:00 2001 From: Paolo Musolino Date: Tue, 18 Mar 2025 19:11:53 +0100 Subject: [PATCH 41/97] Add search parameter to theme retrieval methods --- .../WordPressKit/Services/ThemeServiceRemote.h | 4 ++++ .../WordPressKit/Services/ThemeServiceRemote.m | 18 +++++++++++++----- .../Tests/ThemeServiceRemoteTests.m | 8 +++++--- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/Sources/WordPressKit/Services/ThemeServiceRemote.h b/Sources/WordPressKit/Services/ThemeServiceRemote.h index 3ee51c4a..f0206b90 100644 --- a/Sources/WordPressKit/Services/ThemeServiceRemote.h +++ b/Sources/WordPressKit/Services/ThemeServiceRemote.h @@ -58,6 +58,7 @@ typedef void(^ThemeServiceRemoteFailureBlock)(NSError *error); * @details Includes premium themes even if not purchased. Don't call this method if the list * you want to retrieve is for a specific blog. Use getThemesForBlogId instead. * + * @param search Search term for filtering themes. Cannot be nil. * @param freeOnly Only fetch free themes, if false all WP themes will be returned * @param page Results page to return. * @param success The success handler. Can be nil. @@ -66,6 +67,7 @@ typedef void(^ThemeServiceRemoteFailureBlock)(NSError *error); * @returns A progress object that can be used to track progress and/or cancel the task */ - (NSProgress *)getWPThemesPage:(NSInteger)page + search:(NSString *)search freeOnly:(BOOL)freeOnly success:(ThemeServiceRemoteThemesRequestSuccessBlock)success failure:(ThemeServiceRemoteFailureBlock)failure; @@ -79,6 +81,7 @@ typedef void(^ThemeServiceRemoteFailureBlock)(NSError *error); * this method and not getThemes. * * @param blogId The ID of the blog to get the themes for. Cannot be nil. + * @param search Search term for filtering themes. Cannot be nil. * @param page Results page to return. * @param success The success handler. Can be nil. * @param failure The failure handler. Can be nil. @@ -86,6 +89,7 @@ typedef void(^ThemeServiceRemoteFailureBlock)(NSError *error); * @returns A progress object that can be used to track progress and/or cancel the task */ - (NSProgress *)getThemesForBlogId:(NSNumber *)blogId + search:(NSString *)search page:(NSInteger)page success:(ThemeServiceRemoteThemesRequestSuccessBlock)success failure:(ThemeServiceRemoteFailureBlock)failure; diff --git a/Sources/WordPressKit/Services/ThemeServiceRemote.m b/Sources/WordPressKit/Services/ThemeServiceRemote.m index 97d6e60e..288b78ee 100644 --- a/Sources/WordPressKit/Services/ThemeServiceRemote.m +++ b/Sources/WordPressKit/Services/ThemeServiceRemote.m @@ -13,6 +13,8 @@ static NSString* const ThemeRequestNumberKey = @"number"; static NSInteger const ThemeRequestNumberValue = 50; static NSString* const ThemeRequestPageKey = @"page"; +static NSString* const ThemeRequestSearchKey = @"search"; +static NSString* const ThemeRequestFilterKey = @"filter"; @implementation ThemeServiceRemote @@ -98,11 +100,13 @@ - (NSProgress *)getThemeId:(NSString*)themeId } - (NSProgress *)getWPThemesPage:(NSInteger)page + search:(NSString *)search freeOnly:(BOOL)freeOnly success:(ThemeServiceRemoteThemesRequestSuccessBlock)success failure:(ThemeServiceRemoteFailureBlock)failure { NSParameterAssert(page > 0); + NSParameterAssert([search isKindOfClass:[NSString class]]); NSString *requestUrl = [self pathForEndpoint:@"themes" withVersion:WordPressComRESTAPIVersion_1_2]; @@ -110,7 +114,8 @@ - (NSProgress *)getWPThemesPage:(NSInteger)page NSDictionary *parameters = @{ThemeRequestTierKey: freeOnly ? ThemeRequestTierFreeValue : ThemeRequestTierAllValue, ThemeRequestNumberKey: @(ThemeRequestNumberValue), ThemeRequestPageKey: @(page), - }; + ThemeRequestSearchKey: search + }; return [self getThemesWithRequestUrl:requestUrl page:page @@ -143,17 +148,20 @@ - (NSProgress *)getThemesPage:(NSInteger)page } - (NSProgress *)getThemesForBlogId:(NSNumber *)blogId - page:(NSInteger)page - success:(ThemeServiceRemoteThemesRequestSuccessBlock)success - failure:(ThemeServiceRemoteFailureBlock)failure + search:(NSString *)search + page:(NSInteger)page + success:(ThemeServiceRemoteThemesRequestSuccessBlock)success + failure:(ThemeServiceRemoteFailureBlock)failure { NSParameterAssert([blogId isKindOfClass:[NSNumber class]]); + NSParameterAssert([search isKindOfClass:[NSString class]]); NSParameterAssert(page > 0); NSProgress *progress = [self getThemesForBlogId:blogId page:page apiVersion:WordPressComRESTAPIVersion_1_2 - params:@{ThemeRequestTierKey: ThemeRequestTierAllValue} + params:@{ThemeRequestTierKey: ThemeRequestTierAllValue, + ThemeRequestFilterKey: [NSString stringWithFormat:@"subject:%@", search]} success:success failure:failure]; diff --git a/Tests/WordPressKitTests/Tests/ThemeServiceRemoteTests.m b/Tests/WordPressKitTests/Tests/ThemeServiceRemoteTests.m index e0a6ac7f..2d10a97d 100644 --- a/Tests/WordPressKitTests/Tests/ThemeServiceRemoteTests.m +++ b/Tests/WordPressKitTests/Tests/ThemeServiceRemoteTests.m @@ -224,6 +224,7 @@ - (void)testThatGetThemesWorks }]; XCTAssertNoThrow([service getWPThemesPage:1 + search:@"" freeOnly:NO success:successBlock failure:nil]); @@ -268,9 +269,10 @@ - (void)testThatGetThemesForBlogIdWorks }]; XCTAssertNoThrow([service getThemesForBlogId:blogId - page:1 - success:successBlock - failure:nil]); + search:@"" + page:1 + success:successBlock + failure:nil]); } - (void)testThatGetThemesForBlogIdThrowsExceptionWithoutBlogId From 9959944e7b4322ab824d3b42a74bd27495c8e5a6 Mon Sep 17 00:00:00 2001 From: Paolo Musolino Date: Tue, 18 Mar 2025 19:13:57 +0100 Subject: [PATCH 42/97] update: Change WordPressKit binary target URL and checksum --- Package.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Package.swift b/Package.swift index 965f2427..1fc5c8b3 100644 --- a/Package.swift +++ b/Package.swift @@ -11,8 +11,8 @@ let package = Package( targets: [ .binaryTarget( name: "WordPressKit", - url: "https://github.com/user-attachments/files/19034191/WordPressKit.zip", - checksum: "34f108cba86b5e4334d1c9af79946dbb8b665e270bdd14bc8f7bc0ba7a898583" + url: "https://github.com/user-attachments/files/19325003/WordPressKit.zip", + checksum: "7bab7fb007c1c2bb8b83d0495c32849594451e2d961d289dcee39b84d9c90ebc" ), ] ) From 1e79b7a02e5ecb8ee3c05cb3f7bb4109e04c2ee2 Mon Sep 17 00:00:00 2001 From: Paolo Musolino Date: Tue, 18 Mar 2025 23:46:16 +0100 Subject: [PATCH 43/97] Remove unused filter parameter from ThemeServiceRemote - Delete `ThemeRequestFilterKey` constant in ThemeServiceRemote.m - Remove `search` parameter assertion in `getThemesForBlogId` method - Eliminate filter parameter from `getThemesForBlogId` API call --- Sources/WordPressKit/Services/ThemeServiceRemote.m | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Sources/WordPressKit/Services/ThemeServiceRemote.m b/Sources/WordPressKit/Services/ThemeServiceRemote.m index 288b78ee..a60aac67 100644 --- a/Sources/WordPressKit/Services/ThemeServiceRemote.m +++ b/Sources/WordPressKit/Services/ThemeServiceRemote.m @@ -14,7 +14,6 @@ static NSInteger const ThemeRequestNumberValue = 50; static NSString* const ThemeRequestPageKey = @"page"; static NSString* const ThemeRequestSearchKey = @"search"; -static NSString* const ThemeRequestFilterKey = @"filter"; @implementation ThemeServiceRemote @@ -148,20 +147,17 @@ - (NSProgress *)getThemesPage:(NSInteger)page } - (NSProgress *)getThemesForBlogId:(NSNumber *)blogId - search:(NSString *)search page:(NSInteger)page success:(ThemeServiceRemoteThemesRequestSuccessBlock)success failure:(ThemeServiceRemoteFailureBlock)failure { NSParameterAssert([blogId isKindOfClass:[NSNumber class]]); - NSParameterAssert([search isKindOfClass:[NSString class]]); NSParameterAssert(page > 0); NSProgress *progress = [self getThemesForBlogId:blogId page:page apiVersion:WordPressComRESTAPIVersion_1_2 - params:@{ThemeRequestTierKey: ThemeRequestTierAllValue, - ThemeRequestFilterKey: [NSString stringWithFormat:@"subject:%@", search]} + params:@{ThemeRequestTierKey: ThemeRequestTierAllValue} success:success failure:failure]; From 866940850787f0a7e1eeba406adf6417bdc59165 Mon Sep 17 00:00:00 2001 From: Paolo Musolino Date: Tue, 18 Mar 2025 23:48:37 +0100 Subject: [PATCH 44/97] update `Package.swift` --- Package.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Package.swift b/Package.swift index 1fc5c8b3..04671529 100644 --- a/Package.swift +++ b/Package.swift @@ -11,8 +11,8 @@ let package = Package( targets: [ .binaryTarget( name: "WordPressKit", - url: "https://github.com/user-attachments/files/19325003/WordPressKit.zip", - checksum: "7bab7fb007c1c2bb8b83d0495c32849594451e2d961d289dcee39b84d9c90ebc" + url: "https://github.com/user-attachments/files/19329510/WordPressKit.zip", + checksum: "79d86c26fb143779b25634a042f740343a046ebf615d7b7117b4756c98a1f91f" ), ] ) From b686b1575522e6ca01974351223520a0ebadaf94 Mon Sep 17 00:00:00 2001 From: Paolo Musolino Date: Tue, 18 Mar 2025 23:56:29 +0100 Subject: [PATCH 45/97] Change WordPressComRESTAPIVersion from 1_2 to 2_0 in ThemeServiceRemote, `getWPThemesPage` with search method --- Sources/WordPressKit/Services/ThemeServiceRemote.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/WordPressKit/Services/ThemeServiceRemote.m b/Sources/WordPressKit/Services/ThemeServiceRemote.m index a60aac67..bc54deaf 100644 --- a/Sources/WordPressKit/Services/ThemeServiceRemote.m +++ b/Sources/WordPressKit/Services/ThemeServiceRemote.m @@ -108,7 +108,7 @@ - (NSProgress *)getWPThemesPage:(NSInteger)page NSParameterAssert([search isKindOfClass:[NSString class]]); NSString *requestUrl = [self pathForEndpoint:@"themes" - withVersion:WordPressComRESTAPIVersion_1_2]; + withVersion:WordPressComRESTAPIVersion_2_0]; NSDictionary *parameters = @{ThemeRequestTierKey: freeOnly ? ThemeRequestTierFreeValue : ThemeRequestTierAllValue, ThemeRequestNumberKey: @(ThemeRequestNumberValue), From 5ec2833b6908713422f53298dbc5aa39a2bce06f Mon Sep 17 00:00:00 2001 From: Paolo Musolino Date: Tue, 18 Mar 2025 23:59:01 +0100 Subject: [PATCH 46/97] update package.swift --- Package.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Package.swift b/Package.swift index 04671529..05909874 100644 --- a/Package.swift +++ b/Package.swift @@ -11,8 +11,8 @@ let package = Package( targets: [ .binaryTarget( name: "WordPressKit", - url: "https://github.com/user-attachments/files/19329510/WordPressKit.zip", - checksum: "79d86c26fb143779b25634a042f740343a046ebf615d7b7117b4756c98a1f91f" + url: "https://github.com/user-attachments/files/19329609/WordPressKit.zip", + checksum: "0b29beaa2001b00f38b8d3ecae411ea100bd9867e17c86d0128fa995a7597b55" ), ] ) From f5fbaf50e028fd94986128c1861a63a476158777 Mon Sep 17 00:00:00 2001 From: Paolo Musolino Date: Wed, 19 Mar 2025 10:50:56 +0100 Subject: [PATCH 47/97] update: Package.swift --- Package.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Package.swift b/Package.swift index 05909874..75b680c3 100644 --- a/Package.swift +++ b/Package.swift @@ -11,8 +11,8 @@ let package = Package( targets: [ .binaryTarget( name: "WordPressKit", - url: "https://github.com/user-attachments/files/19329609/WordPressKit.zip", - checksum: "0b29beaa2001b00f38b8d3ecae411ea100bd9867e17c86d0128fa995a7597b55" + url: "https://github.com/user-attachments/files/19337867/WordPressKit.zip", + checksum: "03c45998c7dbb58c2a5a6799c066037b33762b93545d9de764397b7e8ad4173d" ), ] ) From 99f6f70c463a668aa1ee3485355efa9e7be64549 Mon Sep 17 00:00:00 2001 From: Paolo Musolino Date: Wed, 19 Mar 2025 10:55:11 +0100 Subject: [PATCH 48/97] update: ThemeServiceRemoteTests --- Tests/WordPressKitTests/Tests/ThemeServiceRemoteTests.m | 1 - 1 file changed, 1 deletion(-) diff --git a/Tests/WordPressKitTests/Tests/ThemeServiceRemoteTests.m b/Tests/WordPressKitTests/Tests/ThemeServiceRemoteTests.m index 2d10a97d..f7496fa2 100644 --- a/Tests/WordPressKitTests/Tests/ThemeServiceRemoteTests.m +++ b/Tests/WordPressKitTests/Tests/ThemeServiceRemoteTests.m @@ -269,7 +269,6 @@ - (void)testThatGetThemesForBlogIdWorks }]; XCTAssertNoThrow([service getThemesForBlogId:blogId - search:@"" page:1 success:successBlock failure:nil]); From cd033db8938f0f9ce7e3b1922c3d0cc3c111bc77 Mon Sep 17 00:00:00 2001 From: Paolo Musolino Date: Wed, 19 Mar 2025 10:57:47 +0100 Subject: [PATCH 49/97] update: Package.swift --- Package.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Package.swift b/Package.swift index 75b680c3..c39efeb7 100644 --- a/Package.swift +++ b/Package.swift @@ -11,8 +11,8 @@ let package = Package( targets: [ .binaryTarget( name: "WordPressKit", - url: "https://github.com/user-attachments/files/19337867/WordPressKit.zip", - checksum: "03c45998c7dbb58c2a5a6799c066037b33762b93545d9de764397b7e8ad4173d" + url: "https://github.com/user-attachments/files/19338050/WordPressKit.zip", + checksum: "b54214abf4a67e3349ce191463cffe908ec3b5dc2c0989fe5a616c660e1edaa8" ), ] ) From fcb991686c53cda9a5aca840f3acedfafdf83eab Mon Sep 17 00:00:00 2001 From: Paolo Musolino Date: Wed, 19 Mar 2025 11:06:12 +0100 Subject: [PATCH 50/97] update: ThemeServiceRemote header file --- Sources/WordPressKit/Services/ThemeServiceRemote.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/Sources/WordPressKit/Services/ThemeServiceRemote.h b/Sources/WordPressKit/Services/ThemeServiceRemote.h index f0206b90..939cdb4d 100644 --- a/Sources/WordPressKit/Services/ThemeServiceRemote.h +++ b/Sources/WordPressKit/Services/ThemeServiceRemote.h @@ -81,7 +81,6 @@ typedef void(^ThemeServiceRemoteFailureBlock)(NSError *error); * this method and not getThemes. * * @param blogId The ID of the blog to get the themes for. Cannot be nil. - * @param search Search term for filtering themes. Cannot be nil. * @param page Results page to return. * @param success The success handler. Can be nil. * @param failure The failure handler. Can be nil. @@ -89,7 +88,6 @@ typedef void(^ThemeServiceRemoteFailureBlock)(NSError *error); * @returns A progress object that can be used to track progress and/or cancel the task */ - (NSProgress *)getThemesForBlogId:(NSNumber *)blogId - search:(NSString *)search page:(NSInteger)page success:(ThemeServiceRemoteThemesRequestSuccessBlock)success failure:(ThemeServiceRemoteFailureBlock)failure; From 407437b62f9f14dd14ebfed5b8ccb1721a8a3f40 Mon Sep 17 00:00:00 2001 From: Paolo Musolino Date: Wed, 19 Mar 2025 11:07:42 +0100 Subject: [PATCH 51/97] update: package.swift --- Package.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Package.swift b/Package.swift index c39efeb7..5960fd63 100644 --- a/Package.swift +++ b/Package.swift @@ -11,8 +11,8 @@ let package = Package( targets: [ .binaryTarget( name: "WordPressKit", - url: "https://github.com/user-attachments/files/19338050/WordPressKit.zip", - checksum: "b54214abf4a67e3349ce191463cffe908ec3b5dc2c0989fe5a616c660e1edaa8" + url: "https://github.com/user-attachments/files/19338252/WordPressKit.zip", + checksum: "e91be125b5d4e3ba98a0c06b32c71f428cbf3ab1aaa8da08598177ebd24d9a1a" ), ] ) From 2d2d19abb3a12ce443c8b424b0473a10ef1adbd3 Mon Sep 17 00:00:00 2001 From: Paolo Musolino Date: Wed, 19 Mar 2025 11:16:54 +0100 Subject: [PATCH 52/97] fix: endpoint version in method `testThatGetThemesWorks` --- Tests/WordPressKitTests/Tests/ThemeServiceRemoteTests.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/WordPressKitTests/Tests/ThemeServiceRemoteTests.m b/Tests/WordPressKitTests/Tests/ThemeServiceRemoteTests.m index f7496fa2..faf8858b 100644 --- a/Tests/WordPressKitTests/Tests/ThemeServiceRemoteTests.m +++ b/Tests/WordPressKitTests/Tests/ThemeServiceRemoteTests.m @@ -196,7 +196,7 @@ - (void)testThatGetThemesWorks XCTAssertNoThrow(service = [[ThemeServiceRemote alloc] initWithWordPressComRestApi:api]); NSString *url = [service pathForEndpoint:@"themes" - withVersion:WordPressComRESTAPIVersion_1_2]; + withVersion:WordPressComRESTAPIVersion_2_0]; ThemeServiceRemoteThemesRequestSuccessBlock successBlock = ^void (NSArray *themes, BOOL hasMore, NSInteger totalThemeCount) { NSCAssert([themes count] == expectedThemes, @"Expected %ld themes to be returned", expectedThemes); From 221e6c622b615cc16dfee412991ef977d56cfd4b Mon Sep 17 00:00:00 2001 From: Paolo Musolino Date: Wed, 19 Mar 2025 11:19:00 +0100 Subject: [PATCH 53/97] update: Package.swift --- Package.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Package.swift b/Package.swift index 5960fd63..82e37368 100644 --- a/Package.swift +++ b/Package.swift @@ -11,8 +11,8 @@ let package = Package( targets: [ .binaryTarget( name: "WordPressKit", - url: "https://github.com/user-attachments/files/19338252/WordPressKit.zip", - checksum: "e91be125b5d4e3ba98a0c06b32c71f428cbf3ab1aaa8da08598177ebd24d9a1a" + url: "https://github.com/user-attachments/files/19338447/WordPressKit.zip", + checksum: "309f0960e8881e174bec2f9c0f2d833c6c5926e952394bfa87eb532d92709eac" ), ] ) From 3caf721664794d5f32d8941ac1a49159611c5a26 Mon Sep 17 00:00:00 2001 From: Paolo Musolino Date: Wed, 19 Mar 2025 12:42:26 +0100 Subject: [PATCH 54/97] fix: handle optional search parameter in getWPThemesPage method --- .../Services/ThemeServiceRemote.m | 21 +++++++++++-------- .../Tests/ThemeServiceRemoteTests.m | 8 +++---- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/Sources/WordPressKit/Services/ThemeServiceRemote.m b/Sources/WordPressKit/Services/ThemeServiceRemote.m index bc54deaf..496c5a77 100644 --- a/Sources/WordPressKit/Services/ThemeServiceRemote.m +++ b/Sources/WordPressKit/Services/ThemeServiceRemote.m @@ -105,17 +105,20 @@ - (NSProgress *)getWPThemesPage:(NSInteger)page failure:(ThemeServiceRemoteFailureBlock)failure { NSParameterAssert(page > 0); - NSParameterAssert([search isKindOfClass:[NSString class]]); - + NSString *requestUrl = [self pathForEndpoint:@"themes" withVersion:WordPressComRESTAPIVersion_2_0]; - - NSDictionary *parameters = @{ThemeRequestTierKey: freeOnly ? ThemeRequestTierFreeValue : ThemeRequestTierAllValue, - ThemeRequestNumberKey: @(ThemeRequestNumberValue), - ThemeRequestPageKey: @(page), - ThemeRequestSearchKey: search - }; - + + NSMutableDictionary *parameters = [@{ + ThemeRequestTierKey: freeOnly ? ThemeRequestTierFreeValue : ThemeRequestTierAllValue, + ThemeRequestNumberKey: @(ThemeRequestNumberValue), + ThemeRequestPageKey: @(page) + } mutableCopy]; + + if (search) { + parameters[ThemeRequestSearchKey] = search; + } + return [self getThemesWithRequestUrl:requestUrl page:page parameters:parameters diff --git a/Tests/WordPressKitTests/Tests/ThemeServiceRemoteTests.m b/Tests/WordPressKitTests/Tests/ThemeServiceRemoteTests.m index faf8858b..a2eda517 100644 --- a/Tests/WordPressKitTests/Tests/ThemeServiceRemoteTests.m +++ b/Tests/WordPressKitTests/Tests/ThemeServiceRemoteTests.m @@ -224,10 +224,10 @@ - (void)testThatGetThemesWorks }]; XCTAssertNoThrow([service getWPThemesPage:1 - search:@"" - freeOnly:NO - success:successBlock - failure:nil]); + search:nil + freeOnly:NO + success:successBlock + failure:nil]); } - (void)testThatGetThemesForBlogIdWorks From 4fbd973b499f1312103311ff5c883fba19c44dc6 Mon Sep 17 00:00:00 2001 From: Paolo Musolino Date: Wed, 19 Mar 2025 12:45:05 +0100 Subject: [PATCH 55/97] update: Package.swift --- Package.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Package.swift b/Package.swift index 82e37368..9efe0a20 100644 --- a/Package.swift +++ b/Package.swift @@ -11,8 +11,8 @@ let package = Package( targets: [ .binaryTarget( name: "WordPressKit", - url: "https://github.com/user-attachments/files/19338447/WordPressKit.zip", - checksum: "309f0960e8881e174bec2f9c0f2d833c6c5926e952394bfa87eb532d92709eac" + url: "https://github.com/user-attachments/files/19339848/WordPressKit.zip", + checksum: "5bf1ff361992dccf44dfe41b0a442ee4c3c13dc0a1ce9b647a8ed1b976b5c3fc" ), ] ) From 3258ec3eb1fe9df3a93cec3dca0384355c0769ad Mon Sep 17 00:00:00 2001 From: Tony Li Date: Mon, 31 Mar 2025 22:52:53 +1300 Subject: [PATCH 56/97] Exclude unactive Jetpack sites --- Sources/WordPressKit/Models/RemoteBlog.swift | 6 +++++- .../WordPressKit/Services/AccountServiceRemoteREST.m | 11 ++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/Sources/WordPressKit/Models/RemoteBlog.swift b/Sources/WordPressKit/Models/RemoteBlog.swift index 795c9394..8b95bf21 100644 --- a/Sources/WordPressKit/Models/RemoteBlog.swift +++ b/Sources/WordPressKit/Models/RemoteBlog.swift @@ -37,9 +37,12 @@ import Foundation /// Features available for the current blog's plan. public var planActiveFeatures = [String]() - /// Indicates whether it's a jetpack site, or not. + /// Indicates whether the jetpack connection is active. public var jetpack: Bool = false + /// Indicates whether it's a Jetpack connected site. + public var jetpackConnection: Bool = false + /// Boolean indicating whether the current user has Admin privileges, or not. public var isAdmin: Bool = false @@ -70,6 +73,7 @@ import Foundation self.url = json.string(forKey: "URL") ?? "" self.xmlrpc = json.string(forKeyPath: "meta.links.xmlrpc") self.jetpack = json.number(forKey: "jetpack")?.boolValue ?? false + self.jetpackConnection = json.number(forKey: "jetpack_connection")?.boolValue ?? false self.icon = json.string(forKeyPath: "icon.img") self.capabilities = json.object(forKey: "capabilities") as? [String: Bool] ?? [:] self.isAdmin = json.number(forKeyPath: "capabilities.manage_options")?.boolValue ?? false diff --git a/Sources/WordPressKit/Services/AccountServiceRemoteREST.m b/Sources/WordPressKit/Services/AccountServiceRemoteREST.m index ab1041a7..bc339f29 100644 --- a/Sources/WordPressKit/Services/AccountServiceRemoteREST.m +++ b/Sources/WordPressKit/Services/AccountServiceRemoteREST.m @@ -391,7 +391,16 @@ - (NSArray *)remoteBlogsFromJSONArray:(NSArray *)jsonBlogs // Exclude deleted sites from query result, since the app does not handle deleted sites properly. // I tried to use query arguments `site_visibility=visible` and `site_activity=active`, but neither excludes // deleted sites. - return !blog.isDeleted; + if (blog.isDeleted) { + return false; + } + + // Exclude sites that are connected via Jetpack, but without an active Jetpack connection. + if (blog.jetpackConnection && !blog.jetpack) { + return false; + } + + return true; }]; } From aa4ea90ced5a1f1e8644cfbe687bb193ef69e2cf Mon Sep 17 00:00:00 2001 From: Tony Li Date: Mon, 31 Mar 2025 23:08:55 +1300 Subject: [PATCH 57/97] Update xcframework url --- Package.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Package.swift b/Package.swift index 9efe0a20..d8ff4d44 100644 --- a/Package.swift +++ b/Package.swift @@ -11,8 +11,8 @@ let package = Package( targets: [ .binaryTarget( name: "WordPressKit", - url: "https://github.com/user-attachments/files/19339848/WordPressKit.zip", - checksum: "5bf1ff361992dccf44dfe41b0a442ee4c3c13dc0a1ce9b647a8ed1b976b5c3fc" + url: "https://github.com/user-attachments/files/19533607/WordPressKit.zip", + checksum: "d0c8d8994a64ff7ac0cf0fb1cc23c4fa419df011406c327f716b40af7dd8faa0" ), ] ) From 777c6515b1b31dd86f427f7cc3ca41ec920d2add Mon Sep 17 00:00:00 2001 From: Tony Li Date: Tue, 1 Apr 2025 13:36:20 +1300 Subject: [PATCH 58/97] Update docs to be consistent with the HTTP API doc --- Sources/WordPressKit/Models/RemoteBlog.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/WordPressKit/Models/RemoteBlog.swift b/Sources/WordPressKit/Models/RemoteBlog.swift index 8b95bf21..2880832a 100644 --- a/Sources/WordPressKit/Models/RemoteBlog.swift +++ b/Sources/WordPressKit/Models/RemoteBlog.swift @@ -37,10 +37,10 @@ import Foundation /// Features available for the current blog's plan. public var planActiveFeatures = [String]() - /// Indicates whether the jetpack connection is active. + /// Indicates whether the site is a Jetpack site or not. public var jetpack: Bool = false - /// Indicates whether it's a Jetpack connected site. + /// Indicates whether the site is connected to WP.com via `jetpack-connection`. public var jetpackConnection: Bool = false /// Boolean indicating whether the current user has Admin privileges, or not. From b6ada40abe999ce9ab27ceb1d81e244cc1a886c1 Mon Sep 17 00:00:00 2001 From: Tony Li Date: Wed, 9 Apr 2025 12:53:34 +1200 Subject: [PATCH 59/97] Update xcframework url --- Package.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Package.swift b/Package.swift index d8ff4d44..81cffa73 100644 --- a/Package.swift +++ b/Package.swift @@ -11,8 +11,8 @@ let package = Package( targets: [ .binaryTarget( name: "WordPressKit", - url: "https://github.com/user-attachments/files/19533607/WordPressKit.zip", - checksum: "d0c8d8994a64ff7ac0cf0fb1cc23c4fa419df011406c327f716b40af7dd8faa0" + url: "https://github.com/user-attachments/files/19658656/WordPressKit.zip", + checksum: "9172f9b9906e64efe1f3d79f074ad317f1d40c6ce1ec394259b0f99fea6fe8ee" ), ] ) From b45f141def7966c4185aea9500142fbffd5223ad Mon Sep 17 00:00:00 2001 From: Tony Li Date: Tue, 11 Mar 2025 11:26:10 +1300 Subject: [PATCH 60/97] Parse the menu_order property in posts list --- Sources/WordPressKit/Models/RemotePost.h | 1 + Sources/WordPressKit/Services/PostServiceRemoteREST.m | 1 + Sources/WordPressKit/Services/PostServiceRemoteXMLRPC.m | 1 + 3 files changed, 3 insertions(+) diff --git a/Sources/WordPressKit/Models/RemotePost.h b/Sources/WordPressKit/Models/RemotePost.h index 7a06fc5c..e74cee04 100644 --- a/Sources/WordPressKit/Models/RemotePost.h +++ b/Sources/WordPressKit/Models/RemotePost.h @@ -36,6 +36,7 @@ extern NSString * const PostStatusDeleted; @property (nonatomic, strong) NSString *postThumbnailPath; @property (nonatomic, strong) NSString *type; @property (nonatomic, strong) NSString *format; +@property (nonatomic, assign) NSInteger order; /** * A snapshot of the post at the last autosave. diff --git a/Sources/WordPressKit/Services/PostServiceRemoteREST.m b/Sources/WordPressKit/Services/PostServiceRemoteREST.m index f6ecf676..82e809e6 100644 --- a/Sources/WordPressKit/Services/PostServiceRemoteREST.m +++ b/Sources/WordPressKit/Services/PostServiceRemoteREST.m @@ -471,6 +471,7 @@ + (RemotePost *)remotePostFromJSONDictionary:(NSDictionary *)jsonPost { post.postThumbnailPath = [postThumbnail stringForKeyPath:@"URL"]; post.type = jsonPost[@"type"]; post.format = jsonPost[@"format"]; + post.order = [jsonPost numberForKey:@"menu_order"].integerValue; post.commentCount = [jsonPost numberForKeyPath:@"discussion.comment_count"] ?: @0; post.likeCount = [jsonPost numberForKeyPath:@"like_count"] ?: @0; diff --git a/Sources/WordPressKit/Services/PostServiceRemoteXMLRPC.m b/Sources/WordPressKit/Services/PostServiceRemoteXMLRPC.m index d6432e20..30a41613 100644 --- a/Sources/WordPressKit/Services/PostServiceRemoteXMLRPC.m +++ b/Sources/WordPressKit/Services/PostServiceRemoteXMLRPC.m @@ -322,6 +322,7 @@ + (RemotePost *)remotePostFromXMLRPCDictionary:(NSDictionary *)xmlrpcDictionary post.postThumbnailPath = [thumbnailDict stringForKey:@"link"]; post.type = xmlrpcDictionary[@"post_type"]; post.format = xmlrpcDictionary[@"post_format"]; + post.order = [xmlrpcDictionary numberForKey:@"menu_order"].integerValue; post.metadata = xmlrpcDictionary[@"custom_fields"]; From 86f9eef54ed0eb399210001181c5b27c5fd5b184 Mon Sep 17 00:00:00 2001 From: Tony Li Date: Mon, 14 Apr 2025 21:06:41 +1200 Subject: [PATCH 61/97] Update xcframework --- Package.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Package.swift b/Package.swift index 81cffa73..a8fe8a94 100644 --- a/Package.swift +++ b/Package.swift @@ -11,8 +11,8 @@ let package = Package( targets: [ .binaryTarget( name: "WordPressKit", - url: "https://github.com/user-attachments/files/19658656/WordPressKit.zip", - checksum: "9172f9b9906e64efe1f3d79f074ad317f1d40c6ce1ec394259b0f99fea6fe8ee" + url: "https://github.com/user-attachments/files/19732825/WordPressKit.zip", + checksum: "0ecd8b19cd00a4ef363ab6e826f92166c1efa4693db8f3218533510a3f951dbb" ), ] ) From 5f75fa30efb6625a93307933343e7f97516636c4 Mon Sep 17 00:00:00 2001 From: kean Date: Mon, 28 Apr 2025 17:48:39 -0400 Subject: [PATCH 62/97] Add /wpcom/v2/sites/:siteid/subscribers --- Package.swift | 4 +- Sources/CoreAPI/WordPressComRestApi.swift | 6 +- .../Models/RemoteSubscriber.swift | 23 +++++ .../Services/PeopleServiceRemote.swift | 90 +++++++++++++++++++ WordPressKit.xcodeproj/project.pbxproj | 4 + 5 files changed, 122 insertions(+), 5 deletions(-) create mode 100644 Sources/WordPressKit/Models/RemoteSubscriber.swift diff --git a/Package.swift b/Package.swift index a8fe8a94..d0252dff 100644 --- a/Package.swift +++ b/Package.swift @@ -11,8 +11,8 @@ let package = Package( targets: [ .binaryTarget( name: "WordPressKit", - url: "https://github.com/user-attachments/files/19732825/WordPressKit.zip", - checksum: "0ecd8b19cd00a4ef363ab6e826f92166c1efa4693db8f3218533510a3f951dbb" + url: "https://github.com/user-attachments/files/19949670/WordPressKit.zip", + checksum: "69e4a2bec7a641336c4121c1ba23357b6222bf9db8353fe162328852780558ef" ), ] ) diff --git a/Sources/CoreAPI/WordPressComRestApi.swift b/Sources/CoreAPI/WordPressComRestApi.swift index 17b476ef..92d09222 100644 --- a/Sources/CoreAPI/WordPressComRestApi.swift +++ b/Sources/CoreAPI/WordPressComRestApi.swift @@ -376,7 +376,7 @@ open class WordPressComRestApi: NSObject { open func perform( _ method: HTTPRequestBuilder.Method, URLString: String, - parameters: [String: AnyObject]? = nil, + parameters: [String: Any]? = nil, fulfilling progress: Progress? = nil ) async -> APIResult { await perform(method, URLString: URLString, parameters: parameters, fulfilling: progress) { @@ -387,7 +387,7 @@ open class WordPressComRestApi: NSObject { open func perform( _ method: HTTPRequestBuilder.Method, URLString: String, - parameters: [String: AnyObject]? = nil, + parameters: [String: Any]? = nil, fulfilling progress: Progress? = nil, jsonDecoder: JSONDecoder? = nil, type: T.Type = T.self @@ -401,7 +401,7 @@ open class WordPressComRestApi: NSObject { private func perform( _ method: HTTPRequestBuilder.Method, URLString: String, - parameters: [String: AnyObject]?, + parameters: [String: Any]?, fulfilling progress: Progress?, decoder: @escaping (Data) throws -> T ) async -> APIResult { diff --git a/Sources/WordPressKit/Models/RemoteSubscriber.swift b/Sources/WordPressKit/Models/RemoteSubscriber.swift new file mode 100644 index 00000000..f6414b7d --- /dev/null +++ b/Sources/WordPressKit/Models/RemoteSubscriber.swift @@ -0,0 +1,23 @@ +import Foundation + +public struct RemoteSubscriber: Decodable { + public let userID: Int + public let subscriptionID: Int + public let emailAddress: String? + public let dateSubscribed: Date + public let isEmailSubscriber: Bool + public let subscriptionStatus: String? + public let displayName: String? + public let avatar: String? + + private enum CodingKeys: String, CodingKey { + case userID = "user_id" + case subscriptionID = "subscription_id" + case emailAddress = "email_address" + case dateSubscribed = "date_subscribed" + case isEmailSubscriber = "is_email_subscriber" + case subscriptionStatus = "subscription_status" + case displayName = "display_name" + case avatar + } +} diff --git a/Sources/WordPressKit/Services/PeopleServiceRemote.swift b/Sources/WordPressKit/Services/PeopleServiceRemote.swift index e23b26ae..d0854030 100644 --- a/Sources/WordPressKit/Services/PeopleServiceRemote.swift +++ b/Sources/WordPressKit/Services/PeopleServiceRemote.swift @@ -173,6 +173,96 @@ public class PeopleServiceRemote: ServiceRemoteWordPressComREST { }) } + public struct SubscribersParameters { + public var sortField: SortField? + public var sortOrder: SortOrder? + public var filters: [Filter] + + public enum SortField: String { + case dateSubscribed = "date_subscribed" + case email = "email" + case name = "name" + case plan = "plan" + case subscriptionStatus = "subscription_status" + } + + public enum SortOrder: String { + case ascending = "asc" + case descending = "dsc" + } + + public protocol Filter: CustomStringConvertible {} + + public enum FilterSubscriptionType: String, Filter { + case email = "email_subscriber" + case reader = "reader_subscriber" + case unconfirmed = "unconfirmed_subscriber" + case blocked = "blocked_subscriber" + + public var description: String { rawValue } + } + + public enum FilterPaymentType: String, Filter { + case free + case paid + + public var description: String { rawValue } + } + + public init(sortField: SortField? = nil, sortOrder: SortOrder? = nil, filters: [Filter] = []) { + self.sortField = sortField + self.sortOrder = sortOrder + self.filters = filters + } + } + + public struct SubscribersResponse: Decodable { + public var total: Int + public var pages: Int + public var page: Int + public var perPage: Int + public var subscribers: [RemoteSubscriber] + + private enum CodingKeys: String, CodingKey { + case total = "total" + case pages = "pages" + case page = "page" + case perPage = "per_page" + case subscribers = "subscribers" + } + } + + public func getSubscribers( + siteID: Int, + page: Int? = nil, + perPage: Int? = 25, + parameters: SubscribersParameters = .init(), + ) async throws -> SubscribersResponse { + let url = self.path(forEndpoint: "sites/\(siteID)/subscribers", withVersion: ._2_0) + var query: [String: Any] = [:] + if let page { + query["page"] = page + } + if let perPage { + query["per_page"] = perPage + } + if let sortField = parameters.sortField { + query["sort"] = sortField.rawValue + } + if let sortOrder = parameters.sortOrder { + query["sort_order"] = sortOrder.rawValue + } + if !parameters.filters.isEmpty { + query["filters"] = parameters.filters.map { $0.description } + } + return try await wordPressComRestApi.perform( + .get, + URLString: url, + jsonDecoder: JSONDecoder.apiDecoder, + type: SubscribersResponse.self + ).get().body + } + /// Updates a specified User's Role /// /// - Parameters: diff --git a/WordPressKit.xcodeproj/project.pbxproj b/WordPressKit.xcodeproj/project.pbxproj index 23851528..8804e8d3 100644 --- a/WordPressKit.xcodeproj/project.pbxproj +++ b/WordPressKit.xcodeproj/project.pbxproj @@ -50,6 +50,7 @@ 0CCD4C5C2C41700B00B53F9A /* UIDevice+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CCD4C5B2C41700B00B53F9A /* UIDevice+Extensions.swift */; }; 0CCD4C5F2C41711800B53F9A /* NSObject-SafeExpectations in Frameworks */ = {isa = PBXBuildFile; productRef = 0CCD4C5E2C41711800B53F9A /* NSObject-SafeExpectations */; }; 0CCD4C622C41712800B53F9A /* wpxmlrpc in Frameworks */ = {isa = PBXBuildFile; productRef = 0CCD4C612C41712800B53F9A /* wpxmlrpc */; }; + 0CE4E8252DC027AC00056DD9 /* RemoteSubscriber.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CE4E8242DC027AC00056DD9 /* RemoteSubscriber.swift */; }; 0CED1FE82B617CF300E6DD52 /* AtomicSiteServiceRemote.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CED1FE72B617CF300E6DD52 /* AtomicSiteServiceRemote.swift */; }; 0CED1FEB2B617D7D00E6DD52 /* AtomicLogs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CED1FEA2B617D7D00E6DD52 /* AtomicLogs.swift */; }; 1769DEAA24729AFF00F42EFC /* HomepageSettingsServiceRemote.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1769DEA924729AFF00F42EFC /* HomepageSettingsServiceRemote.swift */; }; @@ -824,6 +825,7 @@ 0CB1905F2A2A6943004D3E80 /* blaze-campaigns-search.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "blaze-campaigns-search.json"; sourceTree = ""; }; 0CB190642A2A7569004D3E80 /* BlazeCampaignsSearchResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlazeCampaignsSearchResponse.swift; sourceTree = ""; }; 0CCD4C5B2C41700B00B53F9A /* UIDevice+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIDevice+Extensions.swift"; sourceTree = ""; }; + 0CE4E8242DC027AC00056DD9 /* RemoteSubscriber.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteSubscriber.swift; sourceTree = ""; }; 0CED1FE72B617CF300E6DD52 /* AtomicSiteServiceRemote.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AtomicSiteServiceRemote.swift; sourceTree = ""; }; 0CED1FEA2B617D7D00E6DD52 /* AtomicLogs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AtomicLogs.swift; sourceTree = ""; }; 1769DEA924729AFF00F42EFC /* HomepageSettingsServiceRemote.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomepageSettingsServiceRemote.swift; sourceTree = ""; }; @@ -1866,6 +1868,7 @@ 4A68E3DC294070A7004AC3DC /* RemoteReaderSite.swift */, 4A68E3E0294076C1004AC3DC /* RemoteReaderSiteInfo.swift */, 9F3E0B9A208732B2009CB5BA /* RemoteReaderSiteInfoSubscription.swift */, + 0CE4E8242DC027AC00056DD9 /* RemoteSubscriber.swift */, 4A68E3DE29407100004AC3DC /* RemoteReaderTopic.swift */, 74E2295D1F1E777B0085F7F2 /* RemoteSharingButton.swift */, 7430C9C81F192F260051B8E6 /* RemoteSourcePostAttribution.h */, @@ -3491,6 +3494,7 @@ 3FD634F32BC3AD6200CEDF5E /* Result+Callback.swift in Sources */, B5A4822E20AC6C1A009D95F6 /* WPKitLogging.m in Sources */, 3FE2E97C2BC3A332002CA2E1 /* WordPressComRestApi.swift in Sources */, + 0CE4E8252DC027AC00056DD9 /* RemoteSubscriber.swift in Sources */, FE6C673C2BB739950083ECAB /* NSAttributedString+extensions.swift in Sources */, 7430C9A61F1927180051B8E6 /* ReaderSiteServiceRemote.m in Sources */, FEE4EF57272FDD4B003CDA3C /* RemoteCommentV2.swift in Sources */, From 214ca2198c1581e5225f88be2df78987aedfc4c6 Mon Sep 17 00:00:00 2001 From: kean Date: Mon, 28 Apr 2025 18:31:07 -0400 Subject: [PATCH 63/97] Fix previous Xcode version compatibility --- Package.swift | 4 ++-- Sources/WordPressKit/Services/PeopleServiceRemote.swift | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Package.swift b/Package.swift index d0252dff..c187f3b7 100644 --- a/Package.swift +++ b/Package.swift @@ -11,8 +11,8 @@ let package = Package( targets: [ .binaryTarget( name: "WordPressKit", - url: "https://github.com/user-attachments/files/19949670/WordPressKit.zip", - checksum: "69e4a2bec7a641336c4121c1ba23357b6222bf9db8353fe162328852780558ef" + url: "https://github.com/user-attachments/files/19949703/WordPressKit.zip", + checksum: "68359fda96ca0c7f9d98130c19b6246c2aa2dfdd3ede736be5330270f5e7abdd" ), ] ) diff --git a/Sources/WordPressKit/Services/PeopleServiceRemote.swift b/Sources/WordPressKit/Services/PeopleServiceRemote.swift index d0854030..e4c9dfc3 100644 --- a/Sources/WordPressKit/Services/PeopleServiceRemote.swift +++ b/Sources/WordPressKit/Services/PeopleServiceRemote.swift @@ -236,7 +236,7 @@ public class PeopleServiceRemote: ServiceRemoteWordPressComREST { siteID: Int, page: Int? = nil, perPage: Int? = 25, - parameters: SubscribersParameters = .init(), + parameters: SubscribersParameters = .init() ) async throws -> SubscribersResponse { let url = self.path(forEndpoint: "sites/\(siteID)/subscribers", withVersion: ._2_0) var query: [String: Any] = [:] From 9174ac4a9b8497753a18d8ef44fa12ebe5f4e12f Mon Sep 17 00:00:00 2001 From: kean Date: Mon, 28 Apr 2025 19:02:54 -0400 Subject: [PATCH 64/97] Update tests --- Package.swift | 4 ++-- .../Services/PeopleServiceRemote.swift | 15 +++++--------- .../Mock Data/site-subscribers-response.json | 20 +++++++++++++++++++ .../WordPressKitTests/Tests/JSONLoader.swift | 13 +++++++++++- .../Tests/MockWordPressComRestApi.swift | 2 +- .../Tests/PeopleServiceRemoteTests.swift | 13 ++++++++++++ WordPressKit.xcodeproj/project.pbxproj | 4 ++++ 7 files changed, 57 insertions(+), 14 deletions(-) create mode 100644 Tests/WordPressKitTests/Mock Data/site-subscribers-response.json diff --git a/Package.swift b/Package.swift index c187f3b7..3172714e 100644 --- a/Package.swift +++ b/Package.swift @@ -11,8 +11,8 @@ let package = Package( targets: [ .binaryTarget( name: "WordPressKit", - url: "https://github.com/user-attachments/files/19949703/WordPressKit.zip", - checksum: "68359fda96ca0c7f9d98130c19b6246c2aa2dfdd3ede736be5330270f5e7abdd" + url: "https://github.com/user-attachments/files/19949939/WordPressKit.zip", + checksum: "ba06ff0716595023dd6c98b6a5bc74d4abb35bfb668e24026ffd041460f59137" ), ] ) diff --git a/Sources/WordPressKit/Services/PeopleServiceRemote.swift b/Sources/WordPressKit/Services/PeopleServiceRemote.swift index e4c9dfc3..5c40228b 100644 --- a/Sources/WordPressKit/Services/PeopleServiceRemote.swift +++ b/Sources/WordPressKit/Services/PeopleServiceRemote.swift @@ -220,16 +220,7 @@ public class PeopleServiceRemote: ServiceRemoteWordPressComREST { public var total: Int public var pages: Int public var page: Int - public var perPage: Int public var subscribers: [RemoteSubscriber] - - private enum CodingKeys: String, CodingKey { - case total = "total" - case pages = "pages" - case page = "page" - case perPage = "per_page" - case subscribers = "subscribers" - } } public func getSubscribers( @@ -255,10 +246,14 @@ public class PeopleServiceRemote: ServiceRemoteWordPressComREST { if !parameters.filters.isEmpty { query["filters"] = parameters.filters.map { $0.description } } + + let decoder = JSONDecoder() + decoder.dateDecodingStrategy = JSONDecoder.DateDecodingStrategy.supportMultipleDateFormats + return try await wordPressComRestApi.perform( .get, URLString: url, - jsonDecoder: JSONDecoder.apiDecoder, + jsonDecoder: decoder, type: SubscribersResponse.self ).get().body } diff --git a/Tests/WordPressKitTests/Mock Data/site-subscribers-response.json b/Tests/WordPressKitTests/Mock Data/site-subscribers-response.json new file mode 100644 index 00000000..e6004902 --- /dev/null +++ b/Tests/WordPressKitTests/Mock Data/site-subscribers-response.json @@ -0,0 +1,20 @@ +{ + "total": 1, + "pages": 1, + "page": 1, + "per_page": 100, + "subscribers": [ + { + "user_id": 1, + "subscription_id": 2, + "email_address": "user@example.com", + "date_subscribed": "2025-02-28T19:36:36+00:00", + "is_email_subscriber": false, + "subscription_status": "Not subscribed", + "avatar": "https://0.gravatar.com/avatar/example.jpg", + "display_name": "Test", + "url": "http://example.wordpress.com" + } + ], + "is_owner_subscribed": true +} diff --git a/Tests/WordPressKitTests/Tests/JSONLoader.swift b/Tests/WordPressKitTests/Tests/JSONLoader.swift index e6bda2b9..8fd3b73b 100644 --- a/Tests/WordPressKitTests/Tests/JSONLoader.swift +++ b/Tests/WordPressKitTests/Tests/JSONLoader.swift @@ -12,7 +12,7 @@ import Foundation */ @objc open func loadFile(_ name: String, type: String) -> JSONDictionary? { - let path = Bundle(for: Swift.type(of: self)).path(forResource: name, ofType: type) + let path = JSONLoader.bundle.path(forResource: name, ofType: type) if let unwrappedPath = path { return loadFile(unwrappedPath) @@ -47,4 +47,15 @@ import Foundation return nil } } + + public static func data(named name: String, ext: String = "json") throws -> Data { + guard let url = Bundle(for: JSONLoader.self).url(forResource: name, withExtension: ext) else { + throw URLError(.badURL) + } + return try Data(contentsOf: url) + } + + private static var bundle: Bundle { + Bundle(for: JSONLoader.self) + } } diff --git a/Tests/WordPressKitTests/Tests/MockWordPressComRestApi.swift b/Tests/WordPressKitTests/Tests/MockWordPressComRestApi.swift index 9b552f7f..8edd0079 100644 --- a/Tests/WordPressKitTests/Tests/MockWordPressComRestApi.swift +++ b/Tests/WordPressKitTests/Tests/MockWordPressComRestApi.swift @@ -49,7 +49,7 @@ class MockWordPressComRestApi: WordPressComRestApi { override func perform( _ method: HTTPRequestBuilder.Method, URLString: String, - parameters: [String: AnyObject]? = nil, + parameters: [String: Any]? = nil, fulfilling progress: Progress? = nil, jsonDecoder: JSONDecoder? = nil, type: T.Type = T.self diff --git a/Tests/WordPressKitTests/Tests/PeopleServiceRemoteTests.swift b/Tests/WordPressKitTests/Tests/PeopleServiceRemoteTests.swift index 9ac254eb..1df76fb6 100644 --- a/Tests/WordPressKitTests/Tests/PeopleServiceRemoteTests.swift +++ b/Tests/WordPressKitTests/Tests/PeopleServiceRemoteTests.swift @@ -795,4 +795,17 @@ class PeopleServiceRemoteTests: RemoteTestCase, RESTTestable { waitForExpectations(timeout: timeout, handler: nil) } + func testDecodeSubscribersResponse() throws { + let data = try JSONLoader.data(named: "site-subscribers-response") + + let decoder = JSONDecoder() + decoder.dateDecodingStrategy = JSONDecoder.DateDecodingStrategy.supportMultipleDateFormats + + let response = try decoder.decode(PeopleServiceRemote.SubscribersResponse.self, from: data) + + XCTAssertEqual(response.total, 1) + + let subscriber = try XCTUnwrap(response.subscribers.first) + XCTAssertEqual(subscriber.userID, 1) + } } diff --git a/WordPressKit.xcodeproj/project.pbxproj b/WordPressKit.xcodeproj/project.pbxproj index 8804e8d3..f5ef8417 100644 --- a/WordPressKit.xcodeproj/project.pbxproj +++ b/WordPressKit.xcodeproj/project.pbxproj @@ -24,6 +24,7 @@ 0C363D452C41B468004E241D /* OHHTTPStubs in Frameworks */ = {isa = PBXBuildFile; productRef = 0C363D442C41B468004E241D /* OHHTTPStubs */; }; 0C363D472C41B468004E241D /* OHHTTPStubsSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 0C363D462C41B468004E241D /* OHHTTPStubsSwift */; }; 0C674E302BF3A91300F3B3D4 /* JetpackAIServiceRemote.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C674E2F2BF3A91300F3B3D4 /* JetpackAIServiceRemote.swift */; }; + 0C8069A72DC03E85008DFC2F /* site-subscribers-response.json in Resources */ = {isa = PBXBuildFile; fileRef = 0C8069A62DC03E85008DFC2F /* site-subscribers-response.json */; }; 0C938A062C416789009BA7B2 /* Secret.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C938A052C416789009BA7B2 /* Secret.swift */; }; 0C938A092C4167BC009BA7B2 /* NSString+XMLExtensions.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C938A072C4167BB009BA7B2 /* NSString+XMLExtensions.h */; settings = {ATTRIBUTES = (Public, ); }; }; 0C938A0A2C4167BC009BA7B2 /* NSString+XMLExtensions.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C938A082C4167BB009BA7B2 /* NSString+XMLExtensions.m */; }; @@ -801,6 +802,7 @@ 0C3A2A412A2E7BA500FD91D6 /* CHANGELOG.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = CHANGELOG.md; sourceTree = ""; }; 0C6183C62C420A3700289E73 /* Package.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = ""; }; 0C674E2F2BF3A91300F3B3D4 /* JetpackAIServiceRemote.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JetpackAIServiceRemote.swift; sourceTree = ""; }; + 0C8069A62DC03E85008DFC2F /* site-subscribers-response.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "site-subscribers-response.json"; sourceTree = ""; }; 0C938A052C416789009BA7B2 /* Secret.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Secret.swift; sourceTree = ""; }; 0C938A072C4167BB009BA7B2 /* NSString+XMLExtensions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+XMLExtensions.h"; sourceTree = ""; }; 0C938A082C4167BB009BA7B2 /* NSString+XMLExtensions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+XMLExtensions.m"; sourceTree = ""; }; @@ -2544,6 +2546,7 @@ 9AEAA772215E71C000876E62 /* site-quick-start-success.json */, 74D67F0C1F15C2D70010C5ED /* site-roles-auth-failure.json */, 74D67F0D1F15C2D70010C5ED /* site-roles-bad-json-failure.json */, + 0C8069A62DC03E85008DFC2F /* site-subscribers-response.json */, 74D67F0E1F15C2D70010C5ED /* site-roles-success.json */, D8DB404121EF22B500B8238E /* site-segments-multiple.json */, D813437721F6D7DC0060D99A /* site-segments-single.json */, @@ -3033,6 +3036,7 @@ C738CAF528622953001BE107 /* qrlogin-validate-expired-401.json in Resources */, 937250EC267A15060086075F /* stats-referrer-mark-as-spam.json in Resources */, F3FF8A23279C954100E5C90F /* site-email-followers-get-success.json in Resources */, + 0C8069A72DC03E85008DFC2F /* site-subscribers-response.json in Resources */, 465F889A263B09BF00F4C950 /* wp-block-editor-v1-settings-success-ThemeJSON.json in Resources */, BA9A7F7F24C6895600925E81 /* plugin-directory-jetpack-beta.json in Resources */, E6B0461425E5B6F500DF6F4F /* sites-invites-links-generate.json in Resources */, From 00c78cb39cdabd29720184fd75cafc1437c165cc Mon Sep 17 00:00:00 2001 From: kean Date: Mon, 5 May 2025 10:15:50 -0400 Subject: [PATCH 65/97] Add search to subscribers --- Package.swift | 4 +-- .../Services/PeopleServiceRemote.swift | 32 ++++++++++++------- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/Package.swift b/Package.swift index 3172714e..24a5c41f 100644 --- a/Package.swift +++ b/Package.swift @@ -11,8 +11,8 @@ let package = Package( targets: [ .binaryTarget( name: "WordPressKit", - url: "https://github.com/user-attachments/files/19949939/WordPressKit.zip", - checksum: "ba06ff0716595023dd6c98b6a5bc74d4abb35bfb668e24026ffd041460f59137" + url: "https://github.com/user-attachments/files/20038416/WordPressKit.zip", + checksum: "fa431397e9124b49562fbc5b4f0dccd238fe28f8744826e9a26d14ca57860173" ), ] ) diff --git a/Sources/WordPressKit/Services/PeopleServiceRemote.swift b/Sources/WordPressKit/Services/PeopleServiceRemote.swift index 5c40228b..36856a83 100644 --- a/Sources/WordPressKit/Services/PeopleServiceRemote.swift +++ b/Sources/WordPressKit/Services/PeopleServiceRemote.swift @@ -173,10 +173,11 @@ public class PeopleServiceRemote: ServiceRemoteWordPressComREST { }) } - public struct SubscribersParameters { + public struct SubscribersParameters: Hashable { public var sortField: SortField? public var sortOrder: SortOrder? - public var filters: [Filter] + public var filters: Set + public var search: String? public enum SortField: String { case dateSubscribed = "date_subscribed" @@ -191,25 +192,31 @@ public class PeopleServiceRemote: ServiceRemoteWordPressComREST { case descending = "dsc" } - public protocol Filter: CustomStringConvertible {} + public enum Filter: Hashable { + case subscription(FilterSubscriptionType) + case payment(FilterPaymentType) - public enum FilterSubscriptionType: String, Filter { + var rawValue: String { + switch self { + case .subscription(let filter): filter.rawValue + case .payment(let filter): filter.rawValue + } + } + } + + public enum FilterSubscriptionType: String { case email = "email_subscriber" case reader = "reader_subscriber" case unconfirmed = "unconfirmed_subscriber" case blocked = "blocked_subscriber" - - public var description: String { rawValue } } - public enum FilterPaymentType: String, Filter { + public enum FilterPaymentType: String { case free case paid - - public var description: String { rawValue } } - public init(sortField: SortField? = nil, sortOrder: SortOrder? = nil, filters: [Filter] = []) { + public init(sortField: SortField? = nil, sortOrder: SortOrder? = nil, filters: Set = []) { self.sortField = sortField self.sortOrder = sortOrder self.filters = filters @@ -244,7 +251,10 @@ public class PeopleServiceRemote: ServiceRemoteWordPressComREST { query["sort_order"] = sortOrder.rawValue } if !parameters.filters.isEmpty { - query["filters"] = parameters.filters.map { $0.description } + query["filters"] = parameters.filters.map(\.rawValue) + } + if let search = parameters.search, !search.isEmpty { + query["search"] = search } let decoder = JSONDecoder() From 92c48fcfb40a7f31fe6c0010fdbf9fe459ded223 Mon Sep 17 00:00:00 2001 From: kean Date: Mon, 5 May 2025 10:40:38 -0400 Subject: [PATCH 66/97] Add search to initializer --- Package.swift | 4 ++-- Sources/WordPressKit/Services/PeopleServiceRemote.swift | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Package.swift b/Package.swift index 24a5c41f..eca0bd2c 100644 --- a/Package.swift +++ b/Package.swift @@ -11,8 +11,8 @@ let package = Package( targets: [ .binaryTarget( name: "WordPressKit", - url: "https://github.com/user-attachments/files/20038416/WordPressKit.zip", - checksum: "fa431397e9124b49562fbc5b4f0dccd238fe28f8744826e9a26d14ca57860173" + url: "https://github.com/user-attachments/files/20038728/WordPressKit.zip", + checksum: "7361289ba2ccef75d47dc8c6074072295812314b83194407864575faef1ae140" ), ] ) diff --git a/Sources/WordPressKit/Services/PeopleServiceRemote.swift b/Sources/WordPressKit/Services/PeopleServiceRemote.swift index 36856a83..ca12a838 100644 --- a/Sources/WordPressKit/Services/PeopleServiceRemote.swift +++ b/Sources/WordPressKit/Services/PeopleServiceRemote.swift @@ -216,10 +216,11 @@ public class PeopleServiceRemote: ServiceRemoteWordPressComREST { case paid } - public init(sortField: SortField? = nil, sortOrder: SortOrder? = nil, filters: Set = []) { + public init(sortField: SortField? = nil, sortOrder: SortOrder? = nil, filters: Set = [], search: String? = nil) { self.sortField = sortField self.sortOrder = sortOrder self.filters = filters + self.search = search } } From bb34b0fe64c15795cc1cf68ce514c2da2f77a7bd Mon Sep 17 00:00:00 2001 From: kean Date: Mon, 5 May 2025 11:18:03 -0400 Subject: [PATCH 67/97] Fix missing query --- Package.swift | 4 ++-- Sources/WordPressKit/Services/PeopleServiceRemote.swift | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Package.swift b/Package.swift index eca0bd2c..ac301dac 100644 --- a/Package.swift +++ b/Package.swift @@ -11,8 +11,8 @@ let package = Package( targets: [ .binaryTarget( name: "WordPressKit", - url: "https://github.com/user-attachments/files/20038728/WordPressKit.zip", - checksum: "7361289ba2ccef75d47dc8c6074072295812314b83194407864575faef1ae140" + url: "https://github.com/user-attachments/files/20039232/WordPressKit.zip", + checksum: "6d0d9f96dbe6d810306e5b00635d65c61ae2a0409da519c462bf18f28801db55" ), ] ) diff --git a/Sources/WordPressKit/Services/PeopleServiceRemote.swift b/Sources/WordPressKit/Services/PeopleServiceRemote.swift index ca12a838..fad58f76 100644 --- a/Sources/WordPressKit/Services/PeopleServiceRemote.swift +++ b/Sources/WordPressKit/Services/PeopleServiceRemote.swift @@ -264,6 +264,7 @@ public class PeopleServiceRemote: ServiceRemoteWordPressComREST { return try await wordPressComRestApi.perform( .get, URLString: url, + parameters: query, jsonDecoder: decoder, type: SubscribersResponse.self ).get().body From 40342e8945e143dfa290bd1d503ebf22f577a1ff Mon Sep 17 00:00:00 2001 From: kean Date: Tue, 6 May 2025 09:05:50 -0400 Subject: [PATCH 68/97] Simplify how filters are passed --- Package.swift | 4 +-- .../Services/PeopleServiceRemote.swift | 33 ++++++++----------- 2 files changed, 15 insertions(+), 22 deletions(-) diff --git a/Package.swift b/Package.swift index ac301dac..432ef449 100644 --- a/Package.swift +++ b/Package.swift @@ -11,8 +11,8 @@ let package = Package( targets: [ .binaryTarget( name: "WordPressKit", - url: "https://github.com/user-attachments/files/20039232/WordPressKit.zip", - checksum: "6d0d9f96dbe6d810306e5b00635d65c61ae2a0409da519c462bf18f28801db55" + url: "https://github.com/user-attachments/files/20062492/WordPressKit.zip", + checksum: "dd2bcc029d1d0bdc1b973f006d4c5cb9f0a6219a1fbfd82392c28be8c0bbe2a3" ), ] ) diff --git a/Sources/WordPressKit/Services/PeopleServiceRemote.swift b/Sources/WordPressKit/Services/PeopleServiceRemote.swift index fad58f76..a73b37db 100644 --- a/Sources/WordPressKit/Services/PeopleServiceRemote.swift +++ b/Sources/WordPressKit/Services/PeopleServiceRemote.swift @@ -176,8 +176,8 @@ public class PeopleServiceRemote: ServiceRemoteWordPressComREST { public struct SubscribersParameters: Hashable { public var sortField: SortField? public var sortOrder: SortOrder? - public var filters: Set - public var search: String? + public var subscriptionTypeFilter: FilterSubscriptionType? + public var paymentTypeFilter: FilterPaymentType? public enum SortField: String { case dateSubscribed = "date_subscribed" @@ -192,18 +192,6 @@ public class PeopleServiceRemote: ServiceRemoteWordPressComREST { case descending = "dsc" } - public enum Filter: Hashable { - case subscription(FilterSubscriptionType) - case payment(FilterPaymentType) - - var rawValue: String { - switch self { - case .subscription(let filter): filter.rawValue - case .payment(let filter): filter.rawValue - } - } - } - public enum FilterSubscriptionType: String { case email = "email_subscriber" case reader = "reader_subscriber" @@ -216,11 +204,15 @@ public class PeopleServiceRemote: ServiceRemoteWordPressComREST { case paid } - public init(sortField: SortField? = nil, sortOrder: SortOrder? = nil, filters: Set = [], search: String? = nil) { + var filters: [String] { + [subscriptionTypeFilter?.rawValue, paymentTypeFilter?.rawValue].compactMap { $0 } + } + + public init(sortField: SortField? = nil, sortOrder: SortOrder? = nil, subscriptionTypeFilter: FilterSubscriptionType? = nil, paymentTypeFilter: FilterPaymentType? = nil) { self.sortField = sortField self.sortOrder = sortOrder - self.filters = filters - self.search = search + self.subscriptionTypeFilter = subscriptionTypeFilter + self.paymentTypeFilter = paymentTypeFilter } } @@ -235,7 +227,8 @@ public class PeopleServiceRemote: ServiceRemoteWordPressComREST { siteID: Int, page: Int? = nil, perPage: Int? = 25, - parameters: SubscribersParameters = .init() + parameters: SubscribersParameters = .init(), + search: String? = nil, ) async throws -> SubscribersResponse { let url = self.path(forEndpoint: "sites/\(siteID)/subscribers", withVersion: ._2_0) var query: [String: Any] = [:] @@ -252,9 +245,9 @@ public class PeopleServiceRemote: ServiceRemoteWordPressComREST { query["sort_order"] = sortOrder.rawValue } if !parameters.filters.isEmpty { - query["filters"] = parameters.filters.map(\.rawValue) + query["filters"] = parameters.filters } - if let search = parameters.search, !search.isEmpty { + if let search, !search.isEmpty { query["search"] = search } From 8ffb0d4d3624c8271e49e5e335d6bf59884691ea Mon Sep 17 00:00:00 2001 From: kean Date: Tue, 6 May 2025 11:56:09 -0400 Subject: [PATCH 69/97] Add CaseIterable --- Package.swift | 4 ++-- Sources/WordPressKit/Services/PeopleServiceRemote.swift | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Package.swift b/Package.swift index 432ef449..a2ac129f 100644 --- a/Package.swift +++ b/Package.swift @@ -11,8 +11,8 @@ let package = Package( targets: [ .binaryTarget( name: "WordPressKit", - url: "https://github.com/user-attachments/files/20062492/WordPressKit.zip", - checksum: "dd2bcc029d1d0bdc1b973f006d4c5cb9f0a6219a1fbfd82392c28be8c0bbe2a3" + url: "https://github.com/user-attachments/files/20066712/WordPressKit.zip", + checksum: "0663dd7a2608185cdd5cabb99046cd0146d6ef22a446cf8d2c123823d813b813" ), ] ) diff --git a/Sources/WordPressKit/Services/PeopleServiceRemote.swift b/Sources/WordPressKit/Services/PeopleServiceRemote.swift index a73b37db..4763b61b 100644 --- a/Sources/WordPressKit/Services/PeopleServiceRemote.swift +++ b/Sources/WordPressKit/Services/PeopleServiceRemote.swift @@ -179,7 +179,7 @@ public class PeopleServiceRemote: ServiceRemoteWordPressComREST { public var subscriptionTypeFilter: FilterSubscriptionType? public var paymentTypeFilter: FilterPaymentType? - public enum SortField: String { + public enum SortField: String, CaseIterable { case dateSubscribed = "date_subscribed" case email = "email" case name = "name" @@ -187,19 +187,19 @@ public class PeopleServiceRemote: ServiceRemoteWordPressComREST { case subscriptionStatus = "subscription_status" } - public enum SortOrder: String { + public enum SortOrder: String, CaseIterable { case ascending = "asc" case descending = "dsc" } - public enum FilterSubscriptionType: String { + public enum FilterSubscriptionType: String, CaseIterable { case email = "email_subscriber" case reader = "reader_subscriber" case unconfirmed = "unconfirmed_subscriber" case blocked = "blocked_subscriber" } - public enum FilterPaymentType: String { + public enum FilterPaymentType: String, CaseIterable { case free case paid } From 0bd3c27d0b9b690488c8af6e0ac5219ba3ffe417 Mon Sep 17 00:00:00 2001 From: kean Date: Tue, 6 May 2025 12:21:57 -0400 Subject: [PATCH 70/97] Add @frozen --- Package.swift | 4 ++-- Sources/WordPressKit/Services/PeopleServiceRemote.swift | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Package.swift b/Package.swift index a2ac129f..9f842f83 100644 --- a/Package.swift +++ b/Package.swift @@ -11,8 +11,8 @@ let package = Package( targets: [ .binaryTarget( name: "WordPressKit", - url: "https://github.com/user-attachments/files/20066712/WordPressKit.zip", - checksum: "0663dd7a2608185cdd5cabb99046cd0146d6ef22a446cf8d2c123823d813b813" + url: "https://github.com/user-attachments/files/20067014/WordPressKit.zip", + checksum: "e20c387a1c32306e502326af03f46629140b9d1bc994de3c614890a0fd24b690" ), ] ) diff --git a/Sources/WordPressKit/Services/PeopleServiceRemote.swift b/Sources/WordPressKit/Services/PeopleServiceRemote.swift index 4763b61b..3f7815eb 100644 --- a/Sources/WordPressKit/Services/PeopleServiceRemote.swift +++ b/Sources/WordPressKit/Services/PeopleServiceRemote.swift @@ -179,7 +179,7 @@ public class PeopleServiceRemote: ServiceRemoteWordPressComREST { public var subscriptionTypeFilter: FilterSubscriptionType? public var paymentTypeFilter: FilterPaymentType? - public enum SortField: String, CaseIterable { + @frozen public enum SortField: String, CaseIterable { case dateSubscribed = "date_subscribed" case email = "email" case name = "name" @@ -187,19 +187,19 @@ public class PeopleServiceRemote: ServiceRemoteWordPressComREST { case subscriptionStatus = "subscription_status" } - public enum SortOrder: String, CaseIterable { + @frozen public enum SortOrder: String, CaseIterable { case ascending = "asc" case descending = "dsc" } - public enum FilterSubscriptionType: String, CaseIterable { + @frozen public enum FilterSubscriptionType: String, CaseIterable { case email = "email_subscriber" case reader = "reader_subscriber" case unconfirmed = "unconfirmed_subscriber" case blocked = "blocked_subscriber" } - public enum FilterPaymentType: String, CaseIterable { + @frozen public enum FilterPaymentType: String, CaseIterable { case free case paid } From dc2731551d0139df143dea6b4431475b3bba65a2 Mon Sep 17 00:00:00 2001 From: kean Date: Wed, 7 May 2025 11:38:00 -0400 Subject: [PATCH 71/97] Extract SubscribersServiceRemote --- .../Services/PeopleServiceRemote.swift | 90 ----------------- .../Services/SubscribersServiceRemote.swift | 96 +++++++++++++++++++ .../Tests/PeopleServiceRemoteTests.swift | 14 --- .../Tests/SubscribersServiceRemoteTests.swift | 19 ++++ WordPressKit.xcodeproj/project.pbxproj | 8 ++ 5 files changed, 123 insertions(+), 104 deletions(-) create mode 100644 Sources/WordPressKit/Services/SubscribersServiceRemote.swift create mode 100644 Tests/WordPressKitTests/Tests/SubscribersServiceRemoteTests.swift diff --git a/Sources/WordPressKit/Services/PeopleServiceRemote.swift b/Sources/WordPressKit/Services/PeopleServiceRemote.swift index 3f7815eb..e23b26ae 100644 --- a/Sources/WordPressKit/Services/PeopleServiceRemote.swift +++ b/Sources/WordPressKit/Services/PeopleServiceRemote.swift @@ -173,96 +173,6 @@ public class PeopleServiceRemote: ServiceRemoteWordPressComREST { }) } - public struct SubscribersParameters: Hashable { - public var sortField: SortField? - public var sortOrder: SortOrder? - public var subscriptionTypeFilter: FilterSubscriptionType? - public var paymentTypeFilter: FilterPaymentType? - - @frozen public enum SortField: String, CaseIterable { - case dateSubscribed = "date_subscribed" - case email = "email" - case name = "name" - case plan = "plan" - case subscriptionStatus = "subscription_status" - } - - @frozen public enum SortOrder: String, CaseIterable { - case ascending = "asc" - case descending = "dsc" - } - - @frozen public enum FilterSubscriptionType: String, CaseIterable { - case email = "email_subscriber" - case reader = "reader_subscriber" - case unconfirmed = "unconfirmed_subscriber" - case blocked = "blocked_subscriber" - } - - @frozen public enum FilterPaymentType: String, CaseIterable { - case free - case paid - } - - var filters: [String] { - [subscriptionTypeFilter?.rawValue, paymentTypeFilter?.rawValue].compactMap { $0 } - } - - public init(sortField: SortField? = nil, sortOrder: SortOrder? = nil, subscriptionTypeFilter: FilterSubscriptionType? = nil, paymentTypeFilter: FilterPaymentType? = nil) { - self.sortField = sortField - self.sortOrder = sortOrder - self.subscriptionTypeFilter = subscriptionTypeFilter - self.paymentTypeFilter = paymentTypeFilter - } - } - - public struct SubscribersResponse: Decodable { - public var total: Int - public var pages: Int - public var page: Int - public var subscribers: [RemoteSubscriber] - } - - public func getSubscribers( - siteID: Int, - page: Int? = nil, - perPage: Int? = 25, - parameters: SubscribersParameters = .init(), - search: String? = nil, - ) async throws -> SubscribersResponse { - let url = self.path(forEndpoint: "sites/\(siteID)/subscribers", withVersion: ._2_0) - var query: [String: Any] = [:] - if let page { - query["page"] = page - } - if let perPage { - query["per_page"] = perPage - } - if let sortField = parameters.sortField { - query["sort"] = sortField.rawValue - } - if let sortOrder = parameters.sortOrder { - query["sort_order"] = sortOrder.rawValue - } - if !parameters.filters.isEmpty { - query["filters"] = parameters.filters - } - if let search, !search.isEmpty { - query["search"] = search - } - - let decoder = JSONDecoder() - decoder.dateDecodingStrategy = JSONDecoder.DateDecodingStrategy.supportMultipleDateFormats - - return try await wordPressComRestApi.perform( - .get, - URLString: url, - parameters: query, - jsonDecoder: decoder, - type: SubscribersResponse.self - ).get().body - } - /// Updates a specified User's Role /// /// - Parameters: diff --git a/Sources/WordPressKit/Services/SubscribersServiceRemote.swift b/Sources/WordPressKit/Services/SubscribersServiceRemote.swift new file mode 100644 index 00000000..9c4d552f --- /dev/null +++ b/Sources/WordPressKit/Services/SubscribersServiceRemote.swift @@ -0,0 +1,96 @@ +import Foundation + +public class SubscribersServiceRemote: ServiceRemoteWordPressComREST { + + // MARK: GET + + public struct GetSubscribersParameters: Hashable { + public var sortField: SortField? + public var sortOrder: SortOrder? + public var subscriptionTypeFilter: FilterSubscriptionType? + public var paymentTypeFilter: FilterPaymentType? + + @frozen public enum SortField: String, CaseIterable { + case dateSubscribed = "date_subscribed" + case email = "email" + case name = "name" + case plan = "plan" + case subscriptionStatus = "subscription_status" + } + + @frozen public enum SortOrder: String, CaseIterable { + case ascending = "asc" + case descending = "dsc" + } + + @frozen public enum FilterSubscriptionType: String, CaseIterable { + case email = "email_subscriber" + case reader = "reader_subscriber" + case unconfirmed = "unconfirmed_subscriber" + case blocked = "blocked_subscriber" + } + + @frozen public enum FilterPaymentType: String, CaseIterable { + case free + case paid + } + + var filters: [String] { + [subscriptionTypeFilter?.rawValue, paymentTypeFilter?.rawValue].compactMap { $0 } + } + + public init(sortField: SortField? = nil, sortOrder: SortOrder? = nil, subscriptionTypeFilter: FilterSubscriptionType? = nil, paymentTypeFilter: FilterPaymentType? = nil) { + self.sortField = sortField + self.sortOrder = sortOrder + self.subscriptionTypeFilter = subscriptionTypeFilter + self.paymentTypeFilter = paymentTypeFilter + } + } + + public struct GetSubscribersResponse: Decodable { + public var total: Int + public var pages: Int + public var page: Int + public var subscribers: [RemoteSubscriber] + } + + public func getSubscribers( + siteID: Int, + page: Int? = nil, + perPage: Int? = 25, + parameters: GetSubscribersParameters = .init(), + search: String? = nil, + ) async throws -> GetSubscribersResponse { + let url = self.path(forEndpoint: "sites/\(siteID)/subscribers", withVersion: ._2_0) + var query: [String: Any] = [:] + if let page { + query["page"] = page + } + if let perPage { + query["per_page"] = perPage + } + if let sortField = parameters.sortField { + query["sort"] = sortField.rawValue + } + if let sortOrder = parameters.sortOrder { + query["sort_order"] = sortOrder.rawValue + } + if !parameters.filters.isEmpty { + query["filters"] = parameters.filters + } + if let search, !search.isEmpty { + query["search"] = search + } + + let decoder = JSONDecoder() + decoder.dateDecodingStrategy = JSONDecoder.DateDecodingStrategy.supportMultipleDateFormats + + return try await wordPressComRestApi.perform( + .get, + URLString: url, + parameters: query, + jsonDecoder: decoder, + type: GetSubscribersResponse.self + ).get().body + } +} diff --git a/Tests/WordPressKitTests/Tests/PeopleServiceRemoteTests.swift b/Tests/WordPressKitTests/Tests/PeopleServiceRemoteTests.swift index 1df76fb6..755a2068 100644 --- a/Tests/WordPressKitTests/Tests/PeopleServiceRemoteTests.swift +++ b/Tests/WordPressKitTests/Tests/PeopleServiceRemoteTests.swift @@ -794,18 +794,4 @@ class PeopleServiceRemoteTests: RemoteTestCase, RESTTestable { waitForExpectations(timeout: timeout, handler: nil) } - - func testDecodeSubscribersResponse() throws { - let data = try JSONLoader.data(named: "site-subscribers-response") - - let decoder = JSONDecoder() - decoder.dateDecodingStrategy = JSONDecoder.DateDecodingStrategy.supportMultipleDateFormats - - let response = try decoder.decode(PeopleServiceRemote.SubscribersResponse.self, from: data) - - XCTAssertEqual(response.total, 1) - - let subscriber = try XCTUnwrap(response.subscribers.first) - XCTAssertEqual(subscriber.userID, 1) - } } diff --git a/Tests/WordPressKitTests/Tests/SubscribersServiceRemoteTests.swift b/Tests/WordPressKitTests/Tests/SubscribersServiceRemoteTests.swift new file mode 100644 index 00000000..97c2ea05 --- /dev/null +++ b/Tests/WordPressKitTests/Tests/SubscribersServiceRemoteTests.swift @@ -0,0 +1,19 @@ +import Foundation +import XCTest +@testable import WordPressKit + +class SubscribersServiceRemoteTests: RemoteTestCase, RESTTestable { + func testDecodeSubscribersResponse() throws { + let data = try JSONLoader.data(named: "site-subscribers-response") + + let decoder = JSONDecoder() + decoder.dateDecodingStrategy = JSONDecoder.DateDecodingStrategy.supportMultipleDateFormats + + let response = try decoder.decode(SubscribersServiceRemote.GetSubscribersResponse.self, from: data) + + XCTAssertEqual(response.total, 1) + + let subscriber = try XCTUnwrap(response.subscribers.first) + XCTAssertEqual(subscriber.userID, 1) + } +} diff --git a/WordPressKit.xcodeproj/project.pbxproj b/WordPressKit.xcodeproj/project.pbxproj index f5ef8417..df79b6a4 100644 --- a/WordPressKit.xcodeproj/project.pbxproj +++ b/WordPressKit.xcodeproj/project.pbxproj @@ -51,6 +51,8 @@ 0CCD4C5C2C41700B00B53F9A /* UIDevice+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CCD4C5B2C41700B00B53F9A /* UIDevice+Extensions.swift */; }; 0CCD4C5F2C41711800B53F9A /* NSObject-SafeExpectations in Frameworks */ = {isa = PBXBuildFile; productRef = 0CCD4C5E2C41711800B53F9A /* NSObject-SafeExpectations */; }; 0CCD4C622C41712800B53F9A /* wpxmlrpc in Frameworks */ = {isa = PBXBuildFile; productRef = 0CCD4C612C41712800B53F9A /* wpxmlrpc */; }; + 0CE311BD2DCBB52C003AADB3 /* SubscribersServiceRemote.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CE311BC2DCBB52C003AADB3 /* SubscribersServiceRemote.swift */; }; + 0CE311BF2DCBB588003AADB3 /* SubscribersServiceRemoteTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CE311BE2DCBB588003AADB3 /* SubscribersServiceRemoteTests.swift */; }; 0CE4E8252DC027AC00056DD9 /* RemoteSubscriber.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CE4E8242DC027AC00056DD9 /* RemoteSubscriber.swift */; }; 0CED1FE82B617CF300E6DD52 /* AtomicSiteServiceRemote.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CED1FE72B617CF300E6DD52 /* AtomicSiteServiceRemote.swift */; }; 0CED1FEB2B617D7D00E6DD52 /* AtomicLogs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CED1FEA2B617D7D00E6DD52 /* AtomicLogs.swift */; }; @@ -827,6 +829,8 @@ 0CB1905F2A2A6943004D3E80 /* blaze-campaigns-search.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "blaze-campaigns-search.json"; sourceTree = ""; }; 0CB190642A2A7569004D3E80 /* BlazeCampaignsSearchResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlazeCampaignsSearchResponse.swift; sourceTree = ""; }; 0CCD4C5B2C41700B00B53F9A /* UIDevice+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIDevice+Extensions.swift"; sourceTree = ""; }; + 0CE311BC2DCBB52C003AADB3 /* SubscribersServiceRemote.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscribersServiceRemote.swift; sourceTree = ""; }; + 0CE311BE2DCBB588003AADB3 /* SubscribersServiceRemoteTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscribersServiceRemoteTests.swift; sourceTree = ""; }; 0CE4E8242DC027AC00056DD9 /* RemoteSubscriber.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteSubscriber.swift; sourceTree = ""; }; 0CED1FE72B617CF300E6DD52 /* AtomicSiteServiceRemote.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AtomicSiteServiceRemote.swift; sourceTree = ""; }; 0CED1FEA2B617D7D00E6DD52 /* AtomicLogs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AtomicLogs.swift; sourceTree = ""; }; @@ -1953,6 +1957,7 @@ 74A44DC91F13C533006CD8F4 /* NotificationSyncServiceRemote.swift */, 4625B96B253A357500C04AAD /* PageLayoutServiceRemote.swift */, 74D67F051F1528470010C5ED /* PeopleServiceRemote.swift */, + 0CE311BC2DCBB52C003AADB3 /* SubscribersServiceRemote.swift */, 3F3195AB266FF91100397EE7 /* Plans */, C79719682679007B0072F984 /* Plugin Management */, E1BD95141FD5A2B800CD5CE3 /* PluginDirectoryServiceRemote.swift */, @@ -2081,6 +2086,7 @@ 74A44DD31F13C6D8006CD8F4 /* PushAuthenticationServiceRemoteTests.swift */, 74FC6F3A1F191BB400112505 /* NotificationSyncServiceRemoteTests.swift */, 74D67F091F15C24C0010C5ED /* PeopleServiceRemoteTests.swift */, + 0CE311BE2DCBB588003AADB3 /* SubscribersServiceRemoteTests.swift */, 7433BC031EFC4556002D9E92 /* PlanServiceRemoteTests.swift */, E13EE14B1F332C4400C15787 /* PluginServiceRemoteTests.swift */, E1E89C691FD6BDB1006E7A33 /* PluginDirectoryTests.swift */, @@ -3446,6 +3452,7 @@ 4624222D2548BA0F002B8A12 /* RemoteSiteDesign.swift in Sources */, 74D67F061F1528470010C5ED /* PeopleServiceRemote.swift in Sources */, 0C938A2B2C416DE0009BA7B2 /* DisplayableImageHelper.m in Sources */, + 0CE311BD2DCBB52C003AADB3 /* SubscribersServiceRemote.swift in Sources */, 98DC787522BAEBF200267279 /* StatsAllAnnualInsight.swift in Sources */, 740B23C31F17EE8000067A2A /* RemotePostCategory.m in Sources */, 8B2F4BF124ACE3C30056C08A /* RemoteReaderInterest.swift in Sources */, @@ -3649,6 +3656,7 @@ 4A1DEF46293051C600322608 /* LoggingTests.m in Sources */, 930999521F1658F800F006A1 /* ThemeServiceRemoteTests.m in Sources */, 8BE67ED324AD05D3004DB4C9 /* Decodable+DictionaryTests.swift in Sources */, + 0CE311BF2DCBB588003AADB3 /* SubscribersServiceRemoteTests.swift in Sources */, FEE48EF62A4B3602008A48E0 /* BlogServiceRemote+ActiveFeaturesTests.swift in Sources */, 74B335DA1F06F3D60053A184 /* WordPressComRestApiTests.swift in Sources */, FA87FE0724EB39C4003FBEE3 /* ReaderPostServiceRemote+SubscriptionTests.swift in Sources */, From 5ecc1942f9bbeb0e5a18af77db3b7404c1d4c826 Mon Sep 17 00:00:00 2001 From: kean Date: Wed, 7 May 2025 11:51:16 -0400 Subject: [PATCH 72/97] Add getSubsciberStats --- .../Models/RemoteSubscriber.swift | 20 ++++++------- .../Services/SubscribersServiceRemote.swift | 28 +++++++++++++++++++ .../site-subscriber-stats-response.json | 6 ++++ .../Tests/SubscribersServiceRemoteTests.swift | 13 ++++++++- WordPressKit.xcodeproj/project.pbxproj | 4 +++ 5 files changed, 60 insertions(+), 11 deletions(-) create mode 100644 Tests/WordPressKitTests/Mock Data/site-subscriber-stats-response.json diff --git a/Sources/WordPressKit/Models/RemoteSubscriber.swift b/Sources/WordPressKit/Models/RemoteSubscriber.swift index f6414b7d..ccb1d9f3 100644 --- a/Sources/WordPressKit/Models/RemoteSubscriber.swift +++ b/Sources/WordPressKit/Models/RemoteSubscriber.swift @@ -1,23 +1,23 @@ import Foundation public struct RemoteSubscriber: Decodable { - public let userID: Int - public let subscriptionID: Int + public let subscriberID: Int + public let dotComUserID: Int + public let displayName: String? + public let avatar: String? public let emailAddress: String? public let dateSubscribed: Date - public let isEmailSubscriber: Bool + public let isEmailSubscriptionEnabled: Bool public let subscriptionStatus: String? - public let displayName: String? - public let avatar: String? private enum CodingKeys: String, CodingKey { - case userID = "user_id" - case subscriptionID = "subscription_id" + case subscriberID = "subscription_id" + case dotComUserID = "user_id" + case displayName = "display_name" case emailAddress = "email_address" + case avatar case dateSubscribed = "date_subscribed" - case isEmailSubscriber = "is_email_subscriber" + case isEmailSubscriptionEnabled = "is_email_subscriber" case subscriptionStatus = "subscription_status" - case displayName = "display_name" - case avatar } } diff --git a/Sources/WordPressKit/Services/SubscribersServiceRemote.swift b/Sources/WordPressKit/Services/SubscribersServiceRemote.swift index 9c4d552f..3e525402 100644 --- a/Sources/WordPressKit/Services/SubscribersServiceRemote.swift +++ b/Sources/WordPressKit/Services/SubscribersServiceRemote.swift @@ -54,6 +54,8 @@ public class SubscribersServiceRemote: ServiceRemoteWordPressComREST { public var subscribers: [RemoteSubscriber] } + /// Gets the list of the site subscribers, including WordPress.com users and + /// email subscribers. public func getSubscribers( siteID: Int, page: Int? = nil, @@ -93,4 +95,30 @@ public class SubscribersServiceRemote: ServiceRemoteWordPressComREST { type: GetSubscribersResponse.self ).get().body } + + public struct GetSubscriberStatsResponse: Decodable { + public var emailsSent: Int + public var uniqueOpens: Int + public var uniqueClicks: Int + } + + /// Gets stats for the given subscriber. + /// + /// Example: https://public-api.wordpress.com/wpcom/v2/sites/239619264/individual-subscriber-stats?subscription_id=907116368 + public func getSubsciberStats( + siteID: Int, + subscriberID: Int + ) async throws -> GetSubscriberStatsResponse { + let url = self.path(forEndpoint: "sites/\(siteID)/individual-subscriber-stats", withVersion: ._2_0) + let query: [String: Any] = [ + "subscription_id": 907116368 + ] + return try await wordPressComRestApi.perform( + .get, + URLString: url, + parameters: query, + jsonDecoder: JSONDecoder.apiDecoder, + type: GetSubscriberStatsResponse.self + ).get().body + } } diff --git a/Tests/WordPressKitTests/Mock Data/site-subscriber-stats-response.json b/Tests/WordPressKitTests/Mock Data/site-subscriber-stats-response.json new file mode 100644 index 00000000..fbb84824 --- /dev/null +++ b/Tests/WordPressKitTests/Mock Data/site-subscriber-stats-response.json @@ -0,0 +1,6 @@ +{ + "emails_sent": 1, + "unique_opens": 2, + "unique_clicks": 3, + "blog_registration_date": "2024-12-04 16:00:32" +} diff --git a/Tests/WordPressKitTests/Tests/SubscribersServiceRemoteTests.swift b/Tests/WordPressKitTests/Tests/SubscribersServiceRemoteTests.swift index 97c2ea05..4da74a60 100644 --- a/Tests/WordPressKitTests/Tests/SubscribersServiceRemoteTests.swift +++ b/Tests/WordPressKitTests/Tests/SubscribersServiceRemoteTests.swift @@ -14,6 +14,17 @@ class SubscribersServiceRemoteTests: RemoteTestCase, RESTTestable { XCTAssertEqual(response.total, 1) let subscriber = try XCTUnwrap(response.subscribers.first) - XCTAssertEqual(subscriber.userID, 1) + XCTAssertEqual(subscriber.dotComUserID, 1) + } + + func testDecoderSubscriberStatsResponse() throws { + let data = try JSONLoader.data(named: "site-subscriber-stats-response") + + let decoder = JSONDecoder.apiDecoder + let response = try decoder.decode(SubscribersServiceRemote.GetSubscriberStatsResponse.self, from: data) + + XCTAssertEqual(response.emailsSent, 1) + XCTAssertEqual(response.uniqueOpens, 2) + XCTAssertEqual(response.uniqueClicks, 3) } } diff --git a/WordPressKit.xcodeproj/project.pbxproj b/WordPressKit.xcodeproj/project.pbxproj index df79b6a4..dafbbefe 100644 --- a/WordPressKit.xcodeproj/project.pbxproj +++ b/WordPressKit.xcodeproj/project.pbxproj @@ -53,6 +53,7 @@ 0CCD4C622C41712800B53F9A /* wpxmlrpc in Frameworks */ = {isa = PBXBuildFile; productRef = 0CCD4C612C41712800B53F9A /* wpxmlrpc */; }; 0CE311BD2DCBB52C003AADB3 /* SubscribersServiceRemote.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CE311BC2DCBB52C003AADB3 /* SubscribersServiceRemote.swift */; }; 0CE311BF2DCBB588003AADB3 /* SubscribersServiceRemoteTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CE311BE2DCBB588003AADB3 /* SubscribersServiceRemoteTests.swift */; }; + 0CE311C52DCBB970003AADB3 /* site-subscriber-stats-response.json in Resources */ = {isa = PBXBuildFile; fileRef = 0CE311C42DCBB970003AADB3 /* site-subscriber-stats-response.json */; }; 0CE4E8252DC027AC00056DD9 /* RemoteSubscriber.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CE4E8242DC027AC00056DD9 /* RemoteSubscriber.swift */; }; 0CED1FE82B617CF300E6DD52 /* AtomicSiteServiceRemote.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CED1FE72B617CF300E6DD52 /* AtomicSiteServiceRemote.swift */; }; 0CED1FEB2B617D7D00E6DD52 /* AtomicLogs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CED1FEA2B617D7D00E6DD52 /* AtomicLogs.swift */; }; @@ -831,6 +832,7 @@ 0CCD4C5B2C41700B00B53F9A /* UIDevice+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIDevice+Extensions.swift"; sourceTree = ""; }; 0CE311BC2DCBB52C003AADB3 /* SubscribersServiceRemote.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscribersServiceRemote.swift; sourceTree = ""; }; 0CE311BE2DCBB588003AADB3 /* SubscribersServiceRemoteTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscribersServiceRemoteTests.swift; sourceTree = ""; }; + 0CE311C42DCBB970003AADB3 /* site-subscriber-stats-response.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "site-subscriber-stats-response.json"; sourceTree = ""; }; 0CE4E8242DC027AC00056DD9 /* RemoteSubscriber.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteSubscriber.swift; sourceTree = ""; }; 0CED1FE72B617CF300E6DD52 /* AtomicSiteServiceRemote.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AtomicSiteServiceRemote.swift; sourceTree = ""; }; 0CED1FEA2B617D7D00E6DD52 /* AtomicLogs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AtomicLogs.swift; sourceTree = ""; }; @@ -2553,6 +2555,7 @@ 74D67F0C1F15C2D70010C5ED /* site-roles-auth-failure.json */, 74D67F0D1F15C2D70010C5ED /* site-roles-bad-json-failure.json */, 0C8069A62DC03E85008DFC2F /* site-subscribers-response.json */, + 0CE311C42DCBB970003AADB3 /* site-subscriber-stats-response.json */, 74D67F0E1F15C2D70010C5ED /* site-roles-success.json */, D8DB404121EF22B500B8238E /* site-segments-multiple.json */, D813437721F6D7DC0060D99A /* site-segments-single.json */, @@ -3127,6 +3130,7 @@ E1787DB0200E564B004CB3AF /* timezones.json in Resources */, 93BD275E1EE73442002BB00B /* me-bad-json-failure.json in Resources */, FFE247AF20C891E6002DF3A2 /* WordPressComOAuthWrongPasswordFail.json in Resources */, + 0CE311C52DCBB970003AADB3 /* site-subscriber-stats-response.json in Resources */, F194E1252417EE7E00874408 /* atomic-get-auth-cookie-success.json in Resources */, 731BA83A21DED358000FDFCD /* site-creation-success.json in Resources */, FEFFD99726C158F400F34231 /* share-app-content-success.json in Resources */, From e8e865267f0bf122bcac1367dac2675ab4db06a0 Mon Sep 17 00:00:00 2001 From: kean Date: Wed, 7 May 2025 12:03:07 -0400 Subject: [PATCH 73/97] Add getSubsciberDetails --- Package.swift | 4 +- .../Models/RemoteSubscriber.swift | 23 ----- .../Services/SubscribersServiceRemote.swift | 83 ++++++++++++++++++- .../site-subscriber-get-details-response.json | 15 ++++ .../Tests/SubscribersServiceRemoteTests.swift | 12 +++ WordPressKit.xcodeproj/project.pbxproj | 8 +- 6 files changed, 113 insertions(+), 32 deletions(-) delete mode 100644 Sources/WordPressKit/Models/RemoteSubscriber.swift create mode 100644 Tests/WordPressKitTests/Mock Data/site-subscriber-get-details-response.json diff --git a/Package.swift b/Package.swift index 9f842f83..70e8c781 100644 --- a/Package.swift +++ b/Package.swift @@ -11,8 +11,8 @@ let package = Package( targets: [ .binaryTarget( name: "WordPressKit", - url: "https://github.com/user-attachments/files/20067014/WordPressKit.zip", - checksum: "e20c387a1c32306e502326af03f46629140b9d1bc994de3c614890a0fd24b690" + url: "https://github.com/user-attachments/files/20087743/WordPressKit.zip", + checksum: "138689853d7a65384fa5dae5b5732b40769689a0108f4265e23cc47ca3eea647" ), ] ) diff --git a/Sources/WordPressKit/Models/RemoteSubscriber.swift b/Sources/WordPressKit/Models/RemoteSubscriber.swift deleted file mode 100644 index ccb1d9f3..00000000 --- a/Sources/WordPressKit/Models/RemoteSubscriber.swift +++ /dev/null @@ -1,23 +0,0 @@ -import Foundation - -public struct RemoteSubscriber: Decodable { - public let subscriberID: Int - public let dotComUserID: Int - public let displayName: String? - public let avatar: String? - public let emailAddress: String? - public let dateSubscribed: Date - public let isEmailSubscriptionEnabled: Bool - public let subscriptionStatus: String? - - private enum CodingKeys: String, CodingKey { - case subscriberID = "subscription_id" - case dotComUserID = "user_id" - case displayName = "display_name" - case emailAddress = "email_address" - case avatar - case dateSubscribed = "date_subscribed" - case isEmailSubscriptionEnabled = "is_email_subscriber" - case subscriptionStatus = "subscription_status" - } -} diff --git a/Sources/WordPressKit/Services/SubscribersServiceRemote.swift b/Sources/WordPressKit/Services/SubscribersServiceRemote.swift index 3e525402..bda7f1a5 100644 --- a/Sources/WordPressKit/Services/SubscribersServiceRemote.swift +++ b/Sources/WordPressKit/Services/SubscribersServiceRemote.swift @@ -2,7 +2,7 @@ import Foundation public class SubscribersServiceRemote: ServiceRemoteWordPressComREST { - // MARK: GET + // MARK: GET Subscribers (Paginated List) public struct GetSubscribersParameters: Hashable { public var sortField: SortField? @@ -51,7 +51,29 @@ public class SubscribersServiceRemote: ServiceRemoteWordPressComREST { public var total: Int public var pages: Int public var page: Int - public var subscribers: [RemoteSubscriber] + public var subscribers: [Subscriber] + + public struct Subscriber: Decodable { + public let subscriberID: Int + public let dotComUserID: Int + public let displayName: String? + public let avatar: String? + public let emailAddress: String? + public let dateSubscribed: Date + public let isEmailSubscriptionEnabled: Bool + public let subscriptionStatus: String? + + private enum CodingKeys: String, CodingKey { + case subscriberID = "subscription_id" + case dotComUserID = "user_id" + case displayName = "display_name" + case emailAddress = "email_address" + case avatar + case dateSubscribed = "date_subscribed" + case isEmailSubscriptionEnabled = "is_email_subscriber" + case subscriptionStatus = "subscription_status" + } + } } /// Gets the list of the site subscribers, including WordPress.com users and @@ -96,6 +118,61 @@ public class SubscribersServiceRemote: ServiceRemoteWordPressComREST { ).get().body } + // MARK: GET Subscriber (Individual Details) + + public struct GetSubscriberDetailsResponse: Decodable { + public let subscriberID: Int + public let dotComUserID: Int + public let displayName: String? + public let avatar: String? + public let emailAddress: String? + public let dateSubscribed: Date + public let isEmailSubscriptionEnabled: Bool + public let subscriptionStatus: String? + public let country: Country? + + public struct Country: Decodable { + public var code: String? + public var name: String? + } + + private enum CodingKeys: String, CodingKey { + case subscriberID = "subscription_id" + case dotComUserID = "user_id" + case displayName = "display_name" + case emailAddress = "email_address" + case avatar + case dateSubscribed = "date_subscribed" + case isEmailSubscriptionEnabled = "is_email_subscriber" + case subscriptionStatus = "subscription_status" + case country + } + } + + /// Gets stats for the given subscriber. + /// + /// Example: https://public-api.wordpress.com/wpcom/v2/sites/239619264/subscribers/individual?subscription_id=907116368 + public func getSubsciberDetails( + siteID: Int, + subscriberID: Int + ) async throws -> GetSubscriberDetailsResponse { + let url = self.path(forEndpoint: "sites/\(siteID)/subscribers/individual", withVersion: ._2_0) + let query: [String: Any] = [ + "subscription_id": subscriberID + ] + + let decoder = JSONDecoder() + decoder.dateDecodingStrategy = JSONDecoder.DateDecodingStrategy.supportMultipleDateFormats + + return try await wordPressComRestApi.perform( + .get, + URLString: url, + parameters: query, + jsonDecoder: decoder, + type: GetSubscriberDetailsResponse.self + ).get().body + } + public struct GetSubscriberStatsResponse: Decodable { public var emailsSent: Int public var uniqueOpens: Int @@ -111,7 +188,7 @@ public class SubscribersServiceRemote: ServiceRemoteWordPressComREST { ) async throws -> GetSubscriberStatsResponse { let url = self.path(forEndpoint: "sites/\(siteID)/individual-subscriber-stats", withVersion: ._2_0) let query: [String: Any] = [ - "subscription_id": 907116368 + "subscription_id": subscriberID ] return try await wordPressComRestApi.perform( .get, diff --git a/Tests/WordPressKitTests/Mock Data/site-subscriber-get-details-response.json b/Tests/WordPressKitTests/Mock Data/site-subscriber-get-details-response.json new file mode 100644 index 00000000..41aae359 --- /dev/null +++ b/Tests/WordPressKitTests/Mock Data/site-subscriber-get-details-response.json @@ -0,0 +1,15 @@ +{ + "user_id": 255064965, + "subscription_id": 907116368, + "email_address": "grebenyuk.alexander+test@icloud.com", + "date_subscribed": "2025-04-17T14:40:00+00:00", + "is_email_subscriber": false, + "subscription_status": "Subscribed", + "avatar": "https://0.gravatar.com/avatar/694664524f7d391c4425ab07627f4e44e970f597985d24ce3dc4c27173316c20?s=128&d=https%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D128&r=G", + "display_name": "Alex", + "url": "http://test841027.wordpress.com", + "country": { + "code": "US", + "name": "United States" + } +} diff --git a/Tests/WordPressKitTests/Tests/SubscribersServiceRemoteTests.swift b/Tests/WordPressKitTests/Tests/SubscribersServiceRemoteTests.swift index 4da74a60..3cb7ead3 100644 --- a/Tests/WordPressKitTests/Tests/SubscribersServiceRemoteTests.swift +++ b/Tests/WordPressKitTests/Tests/SubscribersServiceRemoteTests.swift @@ -17,6 +17,18 @@ class SubscribersServiceRemoteTests: RemoteTestCase, RESTTestable { XCTAssertEqual(subscriber.dotComUserID, 1) } + func testDecoderSubscriberDetailsResponse() throws { + let data = try JSONLoader.data(named: "site-subscriber-get-details-response") + + let decoder = JSONDecoder() + decoder.dateDecodingStrategy = JSONDecoder.DateDecodingStrategy.supportMultipleDateFormats + + let response = try decoder.decode(SubscribersServiceRemote.GetSubscriberDetailsResponse.self, from: data) + + XCTAssertEqual(response.country?.code, "US") + XCTAssertEqual(response.country?.name, "United States") + } + func testDecoderSubscriberStatsResponse() throws { let data = try JSONLoader.data(named: "site-subscriber-stats-response") diff --git a/WordPressKit.xcodeproj/project.pbxproj b/WordPressKit.xcodeproj/project.pbxproj index dafbbefe..ac12dead 100644 --- a/WordPressKit.xcodeproj/project.pbxproj +++ b/WordPressKit.xcodeproj/project.pbxproj @@ -54,7 +54,7 @@ 0CE311BD2DCBB52C003AADB3 /* SubscribersServiceRemote.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CE311BC2DCBB52C003AADB3 /* SubscribersServiceRemote.swift */; }; 0CE311BF2DCBB588003AADB3 /* SubscribersServiceRemoteTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CE311BE2DCBB588003AADB3 /* SubscribersServiceRemoteTests.swift */; }; 0CE311C52DCBB970003AADB3 /* site-subscriber-stats-response.json in Resources */ = {isa = PBXBuildFile; fileRef = 0CE311C42DCBB970003AADB3 /* site-subscriber-stats-response.json */; }; - 0CE4E8252DC027AC00056DD9 /* RemoteSubscriber.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CE4E8242DC027AC00056DD9 /* RemoteSubscriber.swift */; }; + 0CE311C72DCBBA01003AADB3 /* site-subscriber-get-details-response.json in Resources */ = {isa = PBXBuildFile; fileRef = 0CE311C62DCBBA01003AADB3 /* site-subscriber-get-details-response.json */; }; 0CED1FE82B617CF300E6DD52 /* AtomicSiteServiceRemote.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CED1FE72B617CF300E6DD52 /* AtomicSiteServiceRemote.swift */; }; 0CED1FEB2B617D7D00E6DD52 /* AtomicLogs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CED1FEA2B617D7D00E6DD52 /* AtomicLogs.swift */; }; 1769DEAA24729AFF00F42EFC /* HomepageSettingsServiceRemote.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1769DEA924729AFF00F42EFC /* HomepageSettingsServiceRemote.swift */; }; @@ -833,7 +833,7 @@ 0CE311BC2DCBB52C003AADB3 /* SubscribersServiceRemote.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscribersServiceRemote.swift; sourceTree = ""; }; 0CE311BE2DCBB588003AADB3 /* SubscribersServiceRemoteTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscribersServiceRemoteTests.swift; sourceTree = ""; }; 0CE311C42DCBB970003AADB3 /* site-subscriber-stats-response.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "site-subscriber-stats-response.json"; sourceTree = ""; }; - 0CE4E8242DC027AC00056DD9 /* RemoteSubscriber.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteSubscriber.swift; sourceTree = ""; }; + 0CE311C62DCBBA01003AADB3 /* site-subscriber-get-details-response.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "site-subscriber-get-details-response.json"; sourceTree = ""; }; 0CED1FE72B617CF300E6DD52 /* AtomicSiteServiceRemote.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AtomicSiteServiceRemote.swift; sourceTree = ""; }; 0CED1FEA2B617D7D00E6DD52 /* AtomicLogs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AtomicLogs.swift; sourceTree = ""; }; 1769DEA924729AFF00F42EFC /* HomepageSettingsServiceRemote.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomepageSettingsServiceRemote.swift; sourceTree = ""; }; @@ -1876,7 +1876,6 @@ 4A68E3DC294070A7004AC3DC /* RemoteReaderSite.swift */, 4A68E3E0294076C1004AC3DC /* RemoteReaderSiteInfo.swift */, 9F3E0B9A208732B2009CB5BA /* RemoteReaderSiteInfoSubscription.swift */, - 0CE4E8242DC027AC00056DD9 /* RemoteSubscriber.swift */, 4A68E3DE29407100004AC3DC /* RemoteReaderTopic.swift */, 74E2295D1F1E777B0085F7F2 /* RemoteSharingButton.swift */, 7430C9C81F192F260051B8E6 /* RemoteSourcePostAttribution.h */, @@ -2556,6 +2555,7 @@ 74D67F0D1F15C2D70010C5ED /* site-roles-bad-json-failure.json */, 0C8069A62DC03E85008DFC2F /* site-subscribers-response.json */, 0CE311C42DCBB970003AADB3 /* site-subscriber-stats-response.json */, + 0CE311C62DCBBA01003AADB3 /* site-subscriber-get-details-response.json */, 74D67F0E1F15C2D70010C5ED /* site-roles-success.json */, D8DB404121EF22B500B8238E /* site-segments-multiple.json */, D813437721F6D7DC0060D99A /* site-segments-single.json */, @@ -3157,6 +3157,7 @@ B04D8C052BB7895A002717A2 /* stats-insight-followers.json in Resources */, 74D67F3B1F15C3740010C5ED /* site-viewers-delete-success.json in Resources */, 93BD275F1EE73442002BB00B /* me-sites-auth-failure.json in Resources */, + 0CE311C72DCBBA01003AADB3 /* site-subscriber-get-details-response.json in Resources */, 74585BA11F0D6F5300E7E667 /* domain-service-empty.json in Resources */, 74C473C51EF33242009918F2 /* site-active-purchases-two-active-success.json in Resources */, 4A3239682B74319400EFD2A8 /* self-hosted-plugins-install.json in Resources */, @@ -3509,7 +3510,6 @@ 3FD634F32BC3AD6200CEDF5E /* Result+Callback.swift in Sources */, B5A4822E20AC6C1A009D95F6 /* WPKitLogging.m in Sources */, 3FE2E97C2BC3A332002CA2E1 /* WordPressComRestApi.swift in Sources */, - 0CE4E8252DC027AC00056DD9 /* RemoteSubscriber.swift in Sources */, FE6C673C2BB739950083ECAB /* NSAttributedString+extensions.swift in Sources */, 7430C9A61F1927180051B8E6 /* ReaderSiteServiceRemote.m in Sources */, FEE4EF57272FDD4B003CDA3C /* RemoteCommentV2.swift in Sources */, From a128446199ff6715ef6876207600b17716df6fe3 Mon Sep 17 00:00:00 2001 From: kean Date: Thu, 8 May 2025 11:37:15 -0400 Subject: [PATCH 74/97] Add support for plans --- Package.swift | 4 +-- .../Services/SubscribersServiceRemote.swift | 32 +++++++++++++++++++ .../site-subscriber-get-details-response.json | 30 ++++++++++++++++- .../Tests/SubscribersServiceRemoteTests.swift | 5 +++ 4 files changed, 68 insertions(+), 3 deletions(-) diff --git a/Package.swift b/Package.swift index 70e8c781..308af351 100644 --- a/Package.swift +++ b/Package.swift @@ -11,8 +11,8 @@ let package = Package( targets: [ .binaryTarget( name: "WordPressKit", - url: "https://github.com/user-attachments/files/20087743/WordPressKit.zip", - checksum: "138689853d7a65384fa5dae5b5732b40769689a0108f4265e23cc47ca3eea647" + url: "https://github.com/user-attachments/files/20105676/WordPressKit.zip", + checksum: "6a446e44dda98d3f5d0d916fbd946d1bf602dfb6124e4ce01aeb7a0c161ee3f6" ), ] ) diff --git a/Sources/WordPressKit/Services/SubscribersServiceRemote.swift b/Sources/WordPressKit/Services/SubscribersServiceRemote.swift index bda7f1a5..a1824917 100644 --- a/Sources/WordPressKit/Services/SubscribersServiceRemote.swift +++ b/Sources/WordPressKit/Services/SubscribersServiceRemote.swift @@ -126,26 +126,58 @@ public class SubscribersServiceRemote: ServiceRemoteWordPressComREST { public let displayName: String? public let avatar: String? public let emailAddress: String? + public let siteURL: String? public let dateSubscribed: Date public let isEmailSubscriptionEnabled: Bool public let subscriptionStatus: String? public let country: Country? + public var plans: [Plan]? public struct Country: Decodable { public var code: String? public var name: String? } + public struct Plan: Decodable { + public let isGift: Bool + public let giftId: Int? + public let paidSubscriptionId: String? + public let status: String + public let title: String + public let currency: String? + public let renewInterval: String? + public let inactiveRenewInterval: String? + public let renewalPrice: Decimal + public let startDate: Date + public let endDate: Date + + enum CodingKeys: String, CodingKey { + case isGift = "is_gift" + case giftId = "gift_id" + case paidSubscriptionId = "paid_subscription_id" + case status + case title + case currency + case renewInterval = "renew_interval" + case inactiveRenewInterval = "inactive_renew_interval" + case renewalPrice = "renewal_price" + case startDate = "start_date" + case endDate = "end_date" + } + } + private enum CodingKeys: String, CodingKey { case subscriberID = "subscription_id" case dotComUserID = "user_id" case displayName = "display_name" case emailAddress = "email_address" case avatar + case siteURL = "url" case dateSubscribed = "date_subscribed" case isEmailSubscriptionEnabled = "is_email_subscriber" case subscriptionStatus = "subscription_status" case country + case plans } } diff --git a/Tests/WordPressKitTests/Mock Data/site-subscriber-get-details-response.json b/Tests/WordPressKitTests/Mock Data/site-subscriber-get-details-response.json index 41aae359..d5b9c1b0 100644 --- a/Tests/WordPressKitTests/Mock Data/site-subscriber-get-details-response.json +++ b/Tests/WordPressKitTests/Mock Data/site-subscriber-get-details-response.json @@ -11,5 +11,33 @@ "country": { "code": "US", "name": "United States" - } + }, + "plans": [ + { + "is_gift": false, + "gift_id": null, + "paid_subscription_id": "12422686", + "status": "active", + "title": "Newsletter Tier", + "currency": "USD", + "renew_interval": "1 month", + "inactive_renew_interval": null, + "renewal_price": 0.5, + "start_date": "2025-01-13T18:51:55+00:00", + "end_date": "2025-02-13T18:51:55+00:00" + }, + { + "is_gift": true, + "gift_id": 31, + "paid_subscription_id": null, + "status": "active", + "title": "Newsletter Tier 3", + "currency": "USD", + "renew_interval": "one-time", + "inactive_renew_interval": null, + "renewal_price": 0, + "start_date": "2025-05-08T14:50:28+00:00", + "end_date": "2025-06-07T14:50:28+00:00" + } + ] } diff --git a/Tests/WordPressKitTests/Tests/SubscribersServiceRemoteTests.swift b/Tests/WordPressKitTests/Tests/SubscribersServiceRemoteTests.swift index 3cb7ead3..a3eb912b 100644 --- a/Tests/WordPressKitTests/Tests/SubscribersServiceRemoteTests.swift +++ b/Tests/WordPressKitTests/Tests/SubscribersServiceRemoteTests.swift @@ -27,6 +27,11 @@ class SubscribersServiceRemoteTests: RemoteTestCase, RESTTestable { XCTAssertEqual(response.country?.code, "US") XCTAssertEqual(response.country?.name, "United States") + + let plan = try XCTUnwrap(response.plans?.first) + XCTAssertFalse(plan.isGift) + XCTAssertEqual(plan.status, "active") + XCTAssertEqual(plan.paidSubscriptionId, "12422686") } func testDecoderSubscriberStatsResponse() throws { From 34f8857dbd9200c58a562c6ee32ead8f99e7e07d Mon Sep 17 00:00:00 2001 From: kean Date: Thu, 8 May 2025 12:58:39 -0400 Subject: [PATCH 75/97] Add SubsciberBasicInfoResponse --- Package.swift | 4 ++-- .../Services/SubscribersServiceRemote.swift | 23 +++++++++++++++++-- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/Package.swift b/Package.swift index 308af351..1fd5e9d8 100644 --- a/Package.swift +++ b/Package.swift @@ -11,8 +11,8 @@ let package = Package( targets: [ .binaryTarget( name: "WordPressKit", - url: "https://github.com/user-attachments/files/20105676/WordPressKit.zip", - checksum: "6a446e44dda98d3f5d0d916fbd946d1bf602dfb6124e4ce01aeb7a0c161ee3f6" + url: "https://github.com/user-attachments/files/20106710/WordPressKit.zip", + checksum: "718a32f677c5ce49bd69f7cb0c8605993370f423aa8f088deab99a6f40dc45ac" ), ] ) diff --git a/Sources/WordPressKit/Services/SubscribersServiceRemote.swift b/Sources/WordPressKit/Services/SubscribersServiceRemote.swift index a1824917..eb7f0476 100644 --- a/Sources/WordPressKit/Services/SubscribersServiceRemote.swift +++ b/Sources/WordPressKit/Services/SubscribersServiceRemote.swift @@ -53,7 +53,7 @@ public class SubscribersServiceRemote: ServiceRemoteWordPressComREST { public var page: Int public var subscribers: [Subscriber] - public struct Subscriber: Decodable { + public struct Subscriber: Decodable, SubsciberBasicInfoResponse { public let subscriberID: Int public let dotComUserID: Int public let displayName: String? @@ -120,7 +120,16 @@ public class SubscribersServiceRemote: ServiceRemoteWordPressComREST { // MARK: GET Subscriber (Individual Details) - public struct GetSubscriberDetailsResponse: Decodable { + public protocol SubsciberBasicInfoResponse { + var dotComUserID: Int { get } + var subscriberID: Int { get } + var displayName: String? { get } + var emailAddress: String? { get } + var avatar: String? { get } + var dateSubscribed: Date { get } + } + + public struct GetSubscriberDetailsResponse: Decodable, SubsciberBasicInfoResponse { public let subscriberID: Int public let dotComUserID: Int public let displayName: String? @@ -231,3 +240,13 @@ public class SubscribersServiceRemote: ServiceRemoteWordPressComREST { ).get().body } } + +extension SubscribersServiceRemote.SubsciberBasicInfoResponse { + public var avatarURL: URL? { + avatar.flatMap(URL.init) + } + + public var isDotComUser: Bool { + dotComUserID > 0 + } +} From f20b9561e9aeca53042e471b15e0d4aea8d162a1 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 9 May 2025 10:34:32 -0400 Subject: [PATCH 76/97] Add type parameter --- Package.swift | 4 ++-- .../Services/SubscribersServiceRemote.swift | 12 ++++++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/Package.swift b/Package.swift index 1fd5e9d8..179790fa 100644 --- a/Package.swift +++ b/Package.swift @@ -11,8 +11,8 @@ let package = Package( targets: [ .binaryTarget( name: "WordPressKit", - url: "https://github.com/user-attachments/files/20106710/WordPressKit.zip", - checksum: "718a32f677c5ce49bd69f7cb0c8605993370f423aa8f088deab99a6f40dc45ac" + url: "https://github.com/user-attachments/files/20123946/WordPressKit.zip", + checksum: "e7905c7d063682c3a3433b4b36578169081c74895db02ec55ec8de2745c799ef" ), ] ) diff --git a/Sources/WordPressKit/Services/SubscribersServiceRemote.swift b/Sources/WordPressKit/Services/SubscribersServiceRemote.swift index eb7f0476..e6513f67 100644 --- a/Sources/WordPressKit/Services/SubscribersServiceRemote.swift +++ b/Sources/WordPressKit/Services/SubscribersServiceRemote.swift @@ -195,11 +195,13 @@ public class SubscribersServiceRemote: ServiceRemoteWordPressComREST { /// Example: https://public-api.wordpress.com/wpcom/v2/sites/239619264/subscribers/individual?subscription_id=907116368 public func getSubsciberDetails( siteID: Int, - subscriberID: Int + subscriberID: Int, + type: String = "email" ) async throws -> GetSubscriberDetailsResponse { let url = self.path(forEndpoint: "sites/\(siteID)/subscribers/individual", withVersion: ._2_0) let query: [String: Any] = [ - "subscription_id": subscriberID + "subscription_id": subscriberID, + "type": type ] let decoder = JSONDecoder() @@ -239,6 +241,12 @@ public class SubscribersServiceRemote: ServiceRemoteWordPressComREST { type: GetSubscriberStatsResponse.self ).get().body } + + // MARK: POST Delete Subscriber + + public func deleteSubscriber() { + + } } extension SubscribersServiceRemote.SubsciberBasicInfoResponse { From 0454d46f6a54ad48c6f9af0745658140852c79ac Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 9 May 2025 11:18:03 -0400 Subject: [PATCH 77/97] Safer decoding --- Package.swift | 4 +- .../Services/SubscribersServiceRemote.swift | 79 +++++++++---------- .../Utility/StringCodingKey.swift | 27 +++++++ ...-get-details-response-invalid-country.json | 15 ++++ .../Tests/SubscribersServiceRemoteTests.swift | 11 +++ WordPressKit.xcodeproj/project.pbxproj | 8 ++ 6 files changed, 101 insertions(+), 43 deletions(-) create mode 100644 Sources/WordPressKit/Utility/StringCodingKey.swift create mode 100644 Tests/WordPressKitTests/Mock Data/site-subscriber-get-details-response-invalid-country.json diff --git a/Package.swift b/Package.swift index 179790fa..27c0046b 100644 --- a/Package.swift +++ b/Package.swift @@ -11,8 +11,8 @@ let package = Package( targets: [ .binaryTarget( name: "WordPressKit", - url: "https://github.com/user-attachments/files/20123946/WordPressKit.zip", - checksum: "e7905c7d063682c3a3433b4b36578169081c74895db02ec55ec8de2745c799ef" + url: "https://github.com/user-attachments/files/20124623/WordPressKit.zip", + checksum: "fb3d6043a07ffe1ba50bbbf3ca8daaa001bff7f05273bad2a113c89705400b1b" ), ] ) diff --git a/Sources/WordPressKit/Services/SubscribersServiceRemote.swift b/Sources/WordPressKit/Services/SubscribersServiceRemote.swift index e6513f67..778826e7 100644 --- a/Sources/WordPressKit/Services/SubscribersServiceRemote.swift +++ b/Sources/WordPressKit/Services/SubscribersServiceRemote.swift @@ -63,15 +63,16 @@ public class SubscribersServiceRemote: ServiceRemoteWordPressComREST { public let isEmailSubscriptionEnabled: Bool public let subscriptionStatus: String? - private enum CodingKeys: String, CodingKey { - case subscriberID = "subscription_id" - case dotComUserID = "user_id" - case displayName = "display_name" - case emailAddress = "email_address" - case avatar - case dateSubscribed = "date_subscribed" - case isEmailSubscriptionEnabled = "is_email_subscriber" - case subscriptionStatus = "subscription_status" + public init(from decoder: any Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + subscriberID = try container.decode(Int.self, forKey: "subscription_id") + dotComUserID = try container.decode(Int.self, forKey: "user_id") + displayName = try? container.decodeIfPresent(String.self, forKey: "display_name") + avatar = try? container.decodeIfPresent(String.self, forKey: "avatar") + emailAddress = try? container.decodeIfPresent(String.self, forKey: "email_address") + dateSubscribed = try container.decode(Date.self, forKey: "date_subscribed") + isEmailSubscriptionEnabled = try container.decode(Bool.self, forKey: "is_email_subscriber") + subscriptionStatus = try? container.decodeIfPresent(String.self, forKey: "subscription_status") } } } @@ -129,7 +130,7 @@ public class SubscribersServiceRemote: ServiceRemoteWordPressComREST { var dateSubscribed: Date { get } } - public struct GetSubscriberDetailsResponse: Decodable, SubsciberBasicInfoResponse { + public final class GetSubscriberDetailsResponse: Decodable, SubsciberBasicInfoResponse { public let subscriberID: Int public let dotComUserID: Int public let displayName: String? @@ -140,7 +141,7 @@ public class SubscribersServiceRemote: ServiceRemoteWordPressComREST { public let isEmailSubscriptionEnabled: Bool public let subscriptionStatus: String? public let country: Country? - public var plans: [Plan]? + public let plans: [Plan]? public struct Country: Decodable { public var code: String? @@ -160,33 +161,35 @@ public class SubscribersServiceRemote: ServiceRemoteWordPressComREST { public let startDate: Date public let endDate: Date - enum CodingKeys: String, CodingKey { - case isGift = "is_gift" - case giftId = "gift_id" - case paidSubscriptionId = "paid_subscription_id" - case status - case title - case currency - case renewInterval = "renew_interval" - case inactiveRenewInterval = "inactive_renew_interval" - case renewalPrice = "renewal_price" - case startDate = "start_date" - case endDate = "end_date" + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + isGift = try container.decode(Bool.self, forKey: "is_gift") + giftId = try container.decodeIfPresent(Int.self, forKey: "gift_id") + paidSubscriptionId = try container.decodeIfPresent(String.self, forKey: "paid_subscription_id") + status = try container.decode(String.self, forKey: "status") + title = try container.decode(String.self, forKey: "title") + currency = try container.decodeIfPresent(String.self, forKey: "currency") + renewInterval = try? container.decodeIfPresent(String.self, forKey: "renew_interval") + inactiveRenewInterval = try? container.decodeIfPresent(String.self, forKey: "inactive_renew_interval") + renewalPrice = try container.decode(Decimal.self, forKey: "renewal_price") + startDate = try container.decode(Date.self, forKey: "start_date") + endDate = try container.decode(Date.self, forKey: "end_date") } } - private enum CodingKeys: String, CodingKey { - case subscriberID = "subscription_id" - case dotComUserID = "user_id" - case displayName = "display_name" - case emailAddress = "email_address" - case avatar - case siteURL = "url" - case dateSubscribed = "date_subscribed" - case isEmailSubscriptionEnabled = "is_email_subscriber" - case subscriptionStatus = "subscription_status" - case country - case plans + public init(from decoder: any Decoder) throws { + let container = try decoder.container(keyedBy: StringCodingKey.self) + subscriberID = try container.decode(Int.self, forKey: "subscription_id") + dotComUserID = try container.decode(Int.self, forKey: "user_id") + displayName = try? container.decodeIfPresent(String.self, forKey: "display_name") + avatar = try? container.decodeIfPresent(String.self, forKey: "avatar") + emailAddress = try? container.decodeIfPresent(String.self, forKey: "email_address") + siteURL = try? container.decodeIfPresent(String.self, forKey: "url") + dateSubscribed = try container.decode(Date.self, forKey: "date_subscribed") + isEmailSubscriptionEnabled = try container.decode(Bool.self, forKey: "is_email_subscriber") + subscriptionStatus = try? container.decodeIfPresent(String.self, forKey: "subscription_status") + country = try? container.decodeIfPresent(Country.self, forKey: "country") + plans = try container.decodeIfPresent([Plan].self, forKey: "plans") } } @@ -241,12 +244,6 @@ public class SubscribersServiceRemote: ServiceRemoteWordPressComREST { type: GetSubscriberStatsResponse.self ).get().body } - - // MARK: POST Delete Subscriber - - public func deleteSubscriber() { - - } } extension SubscribersServiceRemote.SubsciberBasicInfoResponse { diff --git a/Sources/WordPressKit/Utility/StringCodingKey.swift b/Sources/WordPressKit/Utility/StringCodingKey.swift new file mode 100644 index 00000000..9f4c2bb1 --- /dev/null +++ b/Sources/WordPressKit/Utility/StringCodingKey.swift @@ -0,0 +1,27 @@ +import Foundation + +struct StringCodingKey: CodingKey, ExpressibleByStringLiteral { + private let string: String + private var int: Int? + + var stringValue: String { return string } + + init(string: String) { + self.string = string + } + + init?(stringValue: String) { + self.string = stringValue + } + + var intValue: Int? { return int } + + init?(intValue: Int) { + self.string = String(describing: intValue) + self.int = intValue + } + + init(stringLiteral value: String) { + self.string = value + } +} diff --git a/Tests/WordPressKitTests/Mock Data/site-subscriber-get-details-response-invalid-country.json b/Tests/WordPressKitTests/Mock Data/site-subscriber-get-details-response-invalid-country.json new file mode 100644 index 00000000..80542b3d --- /dev/null +++ b/Tests/WordPressKitTests/Mock Data/site-subscriber-get-details-response-invalid-country.json @@ -0,0 +1,15 @@ +{ + "user_id": 255064965, + "subscription_id": 907116368, + "email_address": "grebenyuk.alexander+test@icloud.com", + "date_subscribed": "2025-04-17T14:40:00+00:00", + "is_email_subscriber": false, + "subscription_status": "Subscribed", + "avatar": "https://0.gravatar.com/avatar/694664524f7d391c4425ab07627f4e44e970f597985d24ce3dc4c27173316c20?s=128&d=https%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D128&r=G", + "display_name": "Alex", + "url": "http://test841027.wordpress.com", + "country": { + "code": "", + "name": false + } +} diff --git a/Tests/WordPressKitTests/Tests/SubscribersServiceRemoteTests.swift b/Tests/WordPressKitTests/Tests/SubscribersServiceRemoteTests.swift index a3eb912b..5e6f4bbd 100644 --- a/Tests/WordPressKitTests/Tests/SubscribersServiceRemoteTests.swift +++ b/Tests/WordPressKitTests/Tests/SubscribersServiceRemoteTests.swift @@ -34,6 +34,17 @@ class SubscribersServiceRemoteTests: RemoteTestCase, RESTTestable { XCTAssertEqual(plan.paidSubscriptionId, "12422686") } + func testDecoderSubscriberDetailsInvalidCountry() throws { + let data = try JSONLoader.data(named: "site-subscriber-get-details-response-invalid-country") + + let decoder = JSONDecoder() + decoder.dateDecodingStrategy = JSONDecoder.DateDecodingStrategy.supportMultipleDateFormats + + let response = try decoder.decode(SubscribersServiceRemote.GetSubscriberDetailsResponse.self, from: data) + + XCTAssertNil(response.country) + } + func testDecoderSubscriberStatsResponse() throws { let data = try JSONLoader.data(named: "site-subscriber-stats-response") diff --git a/WordPressKit.xcodeproj/project.pbxproj b/WordPressKit.xcodeproj/project.pbxproj index ac12dead..c6177f16 100644 --- a/WordPressKit.xcodeproj/project.pbxproj +++ b/WordPressKit.xcodeproj/project.pbxproj @@ -51,6 +51,8 @@ 0CCD4C5C2C41700B00B53F9A /* UIDevice+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CCD4C5B2C41700B00B53F9A /* UIDevice+Extensions.swift */; }; 0CCD4C5F2C41711800B53F9A /* NSObject-SafeExpectations in Frameworks */ = {isa = PBXBuildFile; productRef = 0CCD4C5E2C41711800B53F9A /* NSObject-SafeExpectations */; }; 0CCD4C622C41712800B53F9A /* wpxmlrpc in Frameworks */ = {isa = PBXBuildFile; productRef = 0CCD4C612C41712800B53F9A /* wpxmlrpc */; }; + 0CD5D3DD2DCE4F5500B4E679 /* StringCodingKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CD5D3DC2DCE4F5500B4E679 /* StringCodingKey.swift */; }; + 0CD5D3DF2DCE50D900B4E679 /* site-subscriber-get-details-response-invalid-country.json in Resources */ = {isa = PBXBuildFile; fileRef = 0CD5D3DE2DCE50D900B4E679 /* site-subscriber-get-details-response-invalid-country.json */; }; 0CE311BD2DCBB52C003AADB3 /* SubscribersServiceRemote.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CE311BC2DCBB52C003AADB3 /* SubscribersServiceRemote.swift */; }; 0CE311BF2DCBB588003AADB3 /* SubscribersServiceRemoteTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CE311BE2DCBB588003AADB3 /* SubscribersServiceRemoteTests.swift */; }; 0CE311C52DCBB970003AADB3 /* site-subscriber-stats-response.json in Resources */ = {isa = PBXBuildFile; fileRef = 0CE311C42DCBB970003AADB3 /* site-subscriber-stats-response.json */; }; @@ -830,6 +832,8 @@ 0CB1905F2A2A6943004D3E80 /* blaze-campaigns-search.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "blaze-campaigns-search.json"; sourceTree = ""; }; 0CB190642A2A7569004D3E80 /* BlazeCampaignsSearchResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlazeCampaignsSearchResponse.swift; sourceTree = ""; }; 0CCD4C5B2C41700B00B53F9A /* UIDevice+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIDevice+Extensions.swift"; sourceTree = ""; }; + 0CD5D3DC2DCE4F5500B4E679 /* StringCodingKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringCodingKey.swift; sourceTree = ""; }; + 0CD5D3DE2DCE50D900B4E679 /* site-subscriber-get-details-response-invalid-country.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "site-subscriber-get-details-response-invalid-country.json"; sourceTree = ""; }; 0CE311BC2DCBB52C003AADB3 /* SubscribersServiceRemote.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscribersServiceRemote.swift; sourceTree = ""; }; 0CE311BE2DCBB588003AADB3 /* SubscribersServiceRemoteTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscribersServiceRemoteTests.swift; sourceTree = ""; }; 0CE311C42DCBB970003AADB3 /* site-subscriber-stats-response.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "site-subscriber-stats-response.json"; sourceTree = ""; }; @@ -2037,6 +2041,7 @@ 3F3195AC266FF94B00397EE7 /* ZendeskMetadata.swift */, 4AE278432B2FAF6200E4D9B1 /* HTTPProtocolHelpers.swift */, 0CCD4C5B2C41700B00B53F9A /* UIDevice+Extensions.swift */, + 0CD5D3DC2DCE4F5500B4E679 /* StringCodingKey.swift */, ); path = Utility; sourceTree = ""; @@ -2556,6 +2561,7 @@ 0C8069A62DC03E85008DFC2F /* site-subscribers-response.json */, 0CE311C42DCBB970003AADB3 /* site-subscriber-stats-response.json */, 0CE311C62DCBBA01003AADB3 /* site-subscriber-get-details-response.json */, + 0CD5D3DE2DCE50D900B4E679 /* site-subscriber-get-details-response-invalid-country.json */, 74D67F0E1F15C2D70010C5ED /* site-roles-success.json */, D8DB404121EF22B500B8238E /* site-segments-multiple.json */, D813437721F6D7DC0060D99A /* site-segments-single.json */, @@ -3082,6 +3088,7 @@ 74C473CD1EF336BD009918F2 /* site-active-purchases-bad-json-failure.json in Resources */, 436D5645211B801100CEAA33 /* validate-domain-contact-information-response-success.json in Resources */, FE5096652A309DEE00DDD071 /* jetpack-social-with-publicize.json in Resources */, + 0CD5D3DF2DCE50D900B4E679 /* site-subscriber-get-details-response-invalid-country.json in Resources */, 74D67F351F15C3740010C5ED /* site-users-delete-not-member-failure.json in Resources */, E1E89C681FD6B2E9006E7A33 /* plugin-directory-jetpack.json in Resources */, 74D67F201F15C3240010C5ED /* people-validate-invitation-failure.json in Resources */, @@ -3471,6 +3478,7 @@ C7A09A52284104DB003096ED /* QRLoginServiceRemote.swift in Sources */, 4A68E3DD294070A7004AC3DC /* RemoteReaderSite.swift in Sources */, 40AB1ADA200FED25009B533D /* PluginDirectoryFeedPage.swift in Sources */, + 0CD5D3DD2DCE4F5500B4E679 /* StringCodingKey.swift in Sources */, 436D56352118D85800CEAA33 /* WPCountry.swift in Sources */, 74A44DCB1F13C533006CD8F4 /* NotificationSettingsServiceRemote.swift in Sources */, FAD1344525908F5F00A8FEB1 /* JetpackBackupServiceRemote.swift in Sources */, From 9b22001f2c8dfc15cd91f01eae0d3a059c0c3050 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 9 May 2025 11:19:07 -0400 Subject: [PATCH 78/97] Cleanup the test data --- ...ubscriber-get-details-response-invalid-country.json | 10 +++++----- .../site-subscriber-get-details-response.json | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Tests/WordPressKitTests/Mock Data/site-subscriber-get-details-response-invalid-country.json b/Tests/WordPressKitTests/Mock Data/site-subscriber-get-details-response-invalid-country.json index 80542b3d..3b92ec64 100644 --- a/Tests/WordPressKitTests/Mock Data/site-subscriber-get-details-response-invalid-country.json +++ b/Tests/WordPressKitTests/Mock Data/site-subscriber-get-details-response-invalid-country.json @@ -1,13 +1,13 @@ { - "user_id": 255064965, - "subscription_id": 907116368, - "email_address": "grebenyuk.alexander+test@icloud.com", + "user_id": 123, + "subscription_id": 123, + "email_address": "test@example.com", "date_subscribed": "2025-04-17T14:40:00+00:00", "is_email_subscriber": false, "subscription_status": "Subscribed", - "avatar": "https://0.gravatar.com/avatar/694664524f7d391c4425ab07627f4e44e970f597985d24ce3dc4c27173316c20?s=128&d=https%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D128&r=G", + "avatar": "https://example.com/avatar", "display_name": "Alex", - "url": "http://test841027.wordpress.com", + "url": "http://example.wordpress.com", "country": { "code": "", "name": false diff --git a/Tests/WordPressKitTests/Mock Data/site-subscriber-get-details-response.json b/Tests/WordPressKitTests/Mock Data/site-subscriber-get-details-response.json index d5b9c1b0..b7d637e7 100644 --- a/Tests/WordPressKitTests/Mock Data/site-subscriber-get-details-response.json +++ b/Tests/WordPressKitTests/Mock Data/site-subscriber-get-details-response.json @@ -1,13 +1,13 @@ { - "user_id": 255064965, - "subscription_id": 907116368, - "email_address": "grebenyuk.alexander+test@icloud.com", + "user_id": 123, + "subscription_id": 123, + "email_address": "test@example.com", "date_subscribed": "2025-04-17T14:40:00+00:00", "is_email_subscriber": false, "subscription_status": "Subscribed", - "avatar": "https://0.gravatar.com/avatar/694664524f7d391c4425ab07627f4e44e970f597985d24ce3dc4c27173316c20?s=128&d=https%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D128&r=G", + "avatar": "https://example.com/avatar", "display_name": "Alex", - "url": "http://test841027.wordpress.com", + "url": "http://example.wordpress.com", "country": { "code": "US", "name": "United States" From c0ccd265900cea2467bce86aac92acf682dc7123 Mon Sep 17 00:00:00 2001 From: kean Date: Fri, 9 May 2025 15:09:02 -0400 Subject: [PATCH 79/97] Make filter public --- Package.swift | 4 ++-- Sources/WordPressKit/Services/SubscribersServiceRemote.swift | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Package.swift b/Package.swift index 27c0046b..608697ea 100644 --- a/Package.swift +++ b/Package.swift @@ -11,8 +11,8 @@ let package = Package( targets: [ .binaryTarget( name: "WordPressKit", - url: "https://github.com/user-attachments/files/20124623/WordPressKit.zip", - checksum: "fb3d6043a07ffe1ba50bbbf3ca8daaa001bff7f05273bad2a113c89705400b1b" + url: "https://github.com/user-attachments/files/20127687/WordPressKit.zip", + checksum: "bbc81f893eb080a176d018f53d85e6747e529799309c0245c9e204053e75e138" ), ] ) diff --git a/Sources/WordPressKit/Services/SubscribersServiceRemote.swift b/Sources/WordPressKit/Services/SubscribersServiceRemote.swift index 778826e7..e89f0e9e 100644 --- a/Sources/WordPressKit/Services/SubscribersServiceRemote.swift +++ b/Sources/WordPressKit/Services/SubscribersServiceRemote.swift @@ -35,7 +35,7 @@ public class SubscribersServiceRemote: ServiceRemoteWordPressComREST { case paid } - var filters: [String] { + public var filters: [String] { [subscriptionTypeFilter?.rawValue, paymentTypeFilter?.rawValue].compactMap { $0 } } From dfd187739b114fd1d32cbfc8c4cabaa906aa87ac Mon Sep 17 00:00:00 2001 From: kean Date: Mon, 12 May 2025 15:49:07 -0400 Subject: [PATCH 80/97] Add importSubscribers --- Package.swift | 2 +- .../Services/SubscribersServiceRemote.swift | 29 +++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/Package.swift b/Package.swift index 608697ea..3cc289be 100644 --- a/Package.swift +++ b/Package.swift @@ -12,7 +12,7 @@ let package = Package( .binaryTarget( name: "WordPressKit", url: "https://github.com/user-attachments/files/20127687/WordPressKit.zip", - checksum: "bbc81f893eb080a176d018f53d85e6747e529799309c0245c9e204053e75e138" + checksum: "13aa0e5952616a2f01a0f0db370ee7925d58253c2aab6e216671e8a013ab471b" ), ] ) diff --git a/Sources/WordPressKit/Services/SubscribersServiceRemote.swift b/Sources/WordPressKit/Services/SubscribersServiceRemote.swift index e89f0e9e..b8c6770a 100644 --- a/Sources/WordPressKit/Services/SubscribersServiceRemote.swift +++ b/Sources/WordPressKit/Services/SubscribersServiceRemote.swift @@ -244,6 +244,35 @@ public class SubscribersServiceRemote: ServiceRemoteWordPressComREST { type: GetSubscriberStatsResponse.self ).get().body } + + // MARK: POST Import Subscribers + + /// Example: URL: https://public-api.wordpress.com/wpcom/v2/sites/216878809/subscribers/import?_envelope=1 + @discardableResult + public func importSubscribers( + siteID: Int, + emails: [String] + ) async throws -> ImportSubscribersResponse { + let url = self.path(forEndpoint: "sites/\(siteID)/subscribers/import", withVersion: ._2_0) + let parameters: [String: Any] = [ + "emails": emails, + "parse_only": false + ] + return try await wordPressComRestApi.perform( + .post, + URLString: url, + parameters: parameters, + type: ImportSubscribersResponse.self + ).get().body + } + + public struct ImportSubscribersResponse: Decodable { + public let uploadID: Int + + enum CodingKeys: String, CodingKey { + case uploadID = "upload_id" + } + } } extension SubscribersServiceRemote.SubsciberBasicInfoResponse { From cc7fd8a7ea609fc139e7b9d9f53b12c51002ddf4 Mon Sep 17 00:00:00 2001 From: kean Date: Mon, 12 May 2025 15:54:06 -0400 Subject: [PATCH 81/97] Fix download link --- Package.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Package.swift b/Package.swift index 3cc289be..dcc9c7af 100644 --- a/Package.swift +++ b/Package.swift @@ -11,7 +11,7 @@ let package = Package( targets: [ .binaryTarget( name: "WordPressKit", - url: "https://github.com/user-attachments/files/20127687/WordPressKit.zip", + url: "https://github.com/user-attachments/files/20175119/WordPressKit.zip", checksum: "13aa0e5952616a2f01a0f0db370ee7925d58253c2aab6e216671e8a013ab471b" ), ] From ceeeedddb0655c8d32235cec3d4914d56d335941 Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Wed, 18 Jun 2025 10:19:59 +1000 Subject: [PATCH 82/97] DRY `env` definition in CI --- .buildkite/pipeline.yml | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml index 10e07855..76a01fa6 100644 --- a/.buildkite/pipeline.yml +++ b/.buildkite/pipeline.yml @@ -1,12 +1,13 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/buildkite/pipeline-schema/main/schema.json +--- + +env: + IMAGE_ID: xcode-15.3-v3 + # Nodes with values to reuse in the pipeline. common_params: plugins: &common_plugins - automattic/a8c-ci-toolkit#3.1.0 - # Common environment values to use with the `env` key. - env: &common_env - # -v3 contains a workaround for a Simulator boot issue - # See paaHJt-6gL-p2#comment-8712 - IMAGE_ID: xcode-15.3-v3 # This is the default pipeline – it will build and test the app steps: @@ -21,7 +22,6 @@ steps: - fastlane/test_output/report.html - fastlane/test_output/report.junit - .build/derived-data/Logs/**/*.xcactivitylog - env: *common_env plugins: *common_plugins ################# @@ -40,7 +40,6 @@ steps: key: "lint" command: | lint_pod - env: *common_env plugins: *common_plugins ################# @@ -49,7 +48,6 @@ steps: - label: "⬆️ Publish Podspec" key: "publish" command: .buildkite/publish-pod.sh - env: *common_env plugins: *common_plugins depends_on: - "test" From 650e4d99c3fd8d34223eee387c5df164943436fc Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Wed, 18 Jun 2025 10:20:30 +1000 Subject: [PATCH 83/97] Use latest CI toolkit version --- .buildkite/pipeline.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml index 76a01fa6..ca41dea3 100644 --- a/.buildkite/pipeline.yml +++ b/.buildkite/pipeline.yml @@ -7,7 +7,7 @@ env: # Nodes with values to reuse in the pipeline. common_params: plugins: &common_plugins - - automattic/a8c-ci-toolkit#3.1.0 + - automattic/a8c-ci-toolkit#3.5.1 # This is the default pipeline – it will build and test the app steps: From 9b995fbbde97156b87b89d9ea6cd360dc9640806 Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Wed, 18 Jun 2025 10:20:58 +1000 Subject: [PATCH 84/97] AINFRA-283 - Set `queue: mac` explicitly in pipeline This will allow adopting an improved default pipeline upload step on the CI infrastructure side of the setup. It also makes it clear what queue is in use just by looking at the pipeline file. Notice it does not introduce the standard `shared-pipeline-vars` file because to use that we first need the default pipeline upload step in the IaC configuration. --- .buildkite/pipeline.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml index ca41dea3..0fba5896 100644 --- a/.buildkite/pipeline.yml +++ b/.buildkite/pipeline.yml @@ -1,6 +1,9 @@ # yaml-language-server: $schema=https://raw.githubusercontent.com/buildkite/pipeline-schema/main/schema.json --- +agents: + queue: mac + env: IMAGE_ID: xcode-15.3-v3 @@ -54,5 +57,3 @@ steps: - "validate" - "lint" if: build.tag != null - agents: - queue: "mac" From ef77c9658565b1060aa9ceff99c060d65f42379b Mon Sep 17 00:00:00 2001 From: kean Date: Wed, 18 Jun 2025 13:32:18 -0400 Subject: [PATCH 85/97] Add search_text parameter to Activity Logs --- Sources/WordPressKit/Services/ActivityServiceRemote.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Sources/WordPressKit/Services/ActivityServiceRemote.swift b/Sources/WordPressKit/Services/ActivityServiceRemote.swift index 317462bb..99ea34e0 100644 --- a/Sources/WordPressKit/Services/ActivityServiceRemote.swift +++ b/Sources/WordPressKit/Services/ActivityServiceRemote.swift @@ -33,6 +33,7 @@ open class ActivityServiceRemote: ServiceRemoteWordPressComREST { after: Date? = nil, before: Date? = nil, group: [String] = [], + searchText: String? = nil, success: @escaping (_ activities: [Activity], _ hasMore: Bool) -> Void, failure: @escaping (Error) -> Void) { @@ -51,6 +52,9 @@ open class ActivityServiceRemote: ServiceRemoteWordPressComREST { } else if let on = after ?? before { path?.queryItems?.append(URLQueryItem(name: "on", value: formatter.string(from: on))) } + if let searchText, !searchText.isEmpty { + path?.queryItems?.append(URLQueryItem(name: "text_search", value: searchText)) + } guard let endpoint = path?.string else { return From 30dadcab01a980eb16976340c1e9e8a9527ddc05 Mon Sep 17 00:00:00 2001 From: kean Date: Wed, 18 Jun 2025 13:33:16 -0400 Subject: [PATCH 86/97] Update Package.swift --- Package.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Package.swift b/Package.swift index dcc9c7af..4c7c06e8 100644 --- a/Package.swift +++ b/Package.swift @@ -11,8 +11,8 @@ let package = Package( targets: [ .binaryTarget( name: "WordPressKit", - url: "https://github.com/user-attachments/files/20175119/WordPressKit.zip", - checksum: "13aa0e5952616a2f01a0f0db370ee7925d58253c2aab6e216671e8a013ab471b" + url: "https://github.com/user-attachments/files/20801891/WordPressKit.zip", + checksum: "a64680b161f04e5431109b2fcc513ed83356793309b3e1ba8d2fd0a8d128a3c9" ), ] ) From ae3961ce89ac0c43a90e88d4963a04aa92008443 Mon Sep 17 00:00:00 2001 From: kean Date: Thu, 19 Jun 2025 17:19:34 -0400 Subject: [PATCH 87/97] Add /rewindable --- Package.swift | 4 +-- .../Services/ActivityServiceRemote.swift | 25 +++++++++++-------- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/Package.swift b/Package.swift index 4c7c06e8..80b5bbb8 100644 --- a/Package.swift +++ b/Package.swift @@ -11,8 +11,8 @@ let package = Package( targets: [ .binaryTarget( name: "WordPressKit", - url: "https://github.com/user-attachments/files/20801891/WordPressKit.zip", - checksum: "a64680b161f04e5431109b2fcc513ed83356793309b3e1ba8d2fd0a8d128a3c9" + url: "https://github.com/user-attachments/files/20825728/WordPressKit.zip", + checksum: "097a2e55e4ec66b4d8c37bc49181df33c4b62ea9d130fac4de057a0867b68a69" ), ] ) diff --git a/Sources/WordPressKit/Services/ActivityServiceRemote.swift b/Sources/WordPressKit/Services/ActivityServiceRemote.swift index 99ea34e0..56a57cd1 100644 --- a/Sources/WordPressKit/Services/ActivityServiceRemote.swift +++ b/Sources/WordPressKit/Services/ActivityServiceRemote.swift @@ -27,17 +27,22 @@ open class ActivityServiceRemote: ServiceRemoteWordPressComREST { /// /// - Returns: An array of activities and a boolean indicating if there's more activities to fetch. /// - open func getActivityForSite(_ siteID: Int, - offset: Int = 0, - count: Int, - after: Date? = nil, - before: Date? = nil, - group: [String] = [], - searchText: String? = nil, - success: @escaping (_ activities: [Activity], _ hasMore: Bool) -> Void, - failure: @escaping (Error) -> Void) { - + open func getActivityForSite( + _ siteID: Int, + offset: Int = 0, + count: Int, + after: Date? = nil, + before: Date? = nil, + group: [String] = [], + rewindable: Bool? = nil, + searchText: String? = nil, + success: @escaping (_ activities: [Activity], _ hasMore: Bool) -> Void, + failure: @escaping (Error) -> Void + ) { var path = URLComponents(string: "sites/\(siteID)/activity") + if rewindable == true, let currentPath = path?.path { + path?.path = currentPath.appending("/rewindable") + } path?.queryItems = group.map { URLQueryItem(name: "group[]", value: $0) } From 171ff361f88fd3f98604020c9709906fa1c07f4c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Oct 2024 18:12:01 +0000 Subject: [PATCH 88/97] Bump rexml from 3.2.6 to 3.3.9 Bumps [rexml](https://github.com/ruby/rexml) from 3.2.6 to 3.3.9. - [Release notes](https://github.com/ruby/rexml/releases) - [Changelog](https://github.com/ruby/rexml/blob/master/NEWS.md) - [Commits](https://github.com/ruby/rexml/compare/v3.2.6...v3.3.9) --- updated-dependencies: - dependency-name: rexml dependency-type: indirect ... Signed-off-by: dependabot[bot] --- Gemfile.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 296362a9..fbfd2964 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -309,7 +309,7 @@ GEM trailblazer-option (>= 0.1.1, < 0.2.0) uber (< 0.2.0) retriable (3.1.2) - rexml (3.2.6) + rexml (3.3.9) rouge (2.0.7) rubocop (1.60.2) json (~> 2.3) @@ -356,13 +356,13 @@ GEM uber (0.1.0) unicode-display_width (2.5.0) word_wrap (1.0.0) - xcodeproj (1.24.0) + xcodeproj (1.25.1) CFPropertyList (>= 2.3.3, < 4.0) atomos (~> 0.1.3) claide (>= 1.0.2, < 2.0) colored2 (~> 3.1) nanaimo (~> 0.3.0) - rexml (~> 3.2.4) + rexml (>= 3.3.6, < 4.0) xcpretty (0.3.0) rouge (~> 2.0.7) xcpretty-travis-formatter (1.0.1) From ac6c0fa30c8d44a03a4e2c6fb645d26a2862b511 Mon Sep 17 00:00:00 2001 From: Spencer Transier Date: Fri, 11 Oct 2024 12:15:40 +0100 Subject: [PATCH 89/97] Use `linter` queue instead of `default` queue for SwiftLint --- .buildkite/pipeline.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml index 0fba5896..c66648f8 100644 --- a/.buildkite/pipeline.yml +++ b/.buildkite/pipeline.yml @@ -37,7 +37,7 @@ steps: - github_commit_status: context: "SwiftLint" agents: - queue: "default" + queue: "linter" - label: "🧹 Lint" key: "lint" From 05832b6ee8e65d21551dff441750b74c7b570e71 Mon Sep 17 00:00:00 2001 From: Spencer Transier Date: Fri, 1 Nov 2024 16:36:12 -0700 Subject: [PATCH 90/97] Change swiftlint command --- .buildkite/pipeline.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml index c66648f8..8df9223a 100644 --- a/.buildkite/pipeline.yml +++ b/.buildkite/pipeline.yml @@ -31,8 +31,9 @@ steps: # Linters ################# - label: ":swift: SwiftLint" - command: run_swiftlint --strict - plugins: *common_plugins + command: swiftlint + env: + SWIFTLINT_OPTION_STRICT: "true" notify: - github_commit_status: context: "SwiftLint" From 7ad99f146b5053dfd0bb1c11993133c7d6263ee3 Mon Sep 17 00:00:00 2001 From: Spencer Transier Date: Fri, 1 Nov 2024 17:01:13 -0700 Subject: [PATCH 91/97] Remove unneeded quotes --- .buildkite/pipeline.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml index 8df9223a..452b97f6 100644 --- a/.buildkite/pipeline.yml +++ b/.buildkite/pipeline.yml @@ -33,12 +33,12 @@ steps: - label: ":swift: SwiftLint" command: swiftlint env: - SWIFTLINT_OPTION_STRICT: "true" + SWIFTLINT_OPTION_STRICT: true notify: - github_commit_status: - context: "SwiftLint" + context: SwiftLint agents: - queue: "linter" + queue: linter - label: "🧹 Lint" key: "lint" From 820fec8d8d2b3e9e041184ae9e1c165daeb0e6ab Mon Sep 17 00:00:00 2001 From: Hicham Boushaba Date: Thu, 14 Nov 2024 15:36:26 +0100 Subject: [PATCH 92/97] Add support for sending magic links to inexistent accounts --- .../Services/AccountServiceRemoteREST.h | 15 +++++++++++ .../Services/AccountServiceRemoteREST.m | 26 ++++++++++++++++--- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/Sources/WordPressKit/Services/AccountServiceRemoteREST.h b/Sources/WordPressKit/Services/AccountServiceRemoteREST.h index d110bc95..a4c0223f 100644 --- a/Sources/WordPressKit/Services/AccountServiceRemoteREST.h +++ b/Sources/WordPressKit/Services/AccountServiceRemoteREST.h @@ -17,6 +17,21 @@ extern MagicLinkFlow const MagicLinkFlowSignup; @interface AccountServiceRemoteREST : ServiceRemoteWordPressComREST +/** +* @brief Request an authentication link be sent to the email address provided. +* + * @param success The block that will be executed on success. Can be nil. + * @param failure The block that will be executed on failure. Can be nil. + */ +- (void)requestWPComAuthLinkForEmail:(NSString *)email + clientID:(NSString *)clientID + clientSecret:(NSString *)clientSecret + source:(MagicLinkSource)source + wpcomScheme:(NSString *)scheme + createAccountIfNotFound:(BOOL)createAccountIfNotFound + success:(void (^)(void))success + failure:(void (^)(NSError *error))failure; + /** * @brief Request an authentication link be sent to the email address provided. * diff --git a/Sources/WordPressKit/Services/AccountServiceRemoteREST.m b/Sources/WordPressKit/Services/AccountServiceRemoteREST.m index bc339f29..483893f6 100644 --- a/Sources/WordPressKit/Services/AccountServiceRemoteREST.m +++ b/Sources/WordPressKit/Services/AccountServiceRemoteREST.m @@ -244,17 +244,19 @@ - (void)requestWPComAuthLinkForEmail:(NSString *)email clientSecret:(NSString *)clientSecret source:(MagicLinkSource)source wpcomScheme:(NSString *)scheme + createAccountIfNotFound:(BOOL)createAccountIfNotFound success:(void (^)(void))success failure:(void (^)(NSError *error))failure { NSString *path = [self pathForEndpoint:@"auth/send-login-email" withVersion:WordPressComRESTAPIVersion_1_3]; - + NSDictionary *extraParams = @{ MagicLinkParameterFlow: MagicLinkFlowLogin, - MagicLinkParameterSource: source + MagicLinkParameterSource: source, + @"create_account": createAccountIfNotFound ? @"true" : @"false" }; - + [self requestWPComMagicLinkForEmail:email path:path clientID:clientID @@ -265,6 +267,24 @@ - (void)requestWPComAuthLinkForEmail:(NSString *)email failure:failure]; } +- (void)requestWPComAuthLinkForEmail:(NSString *)email + clientID:(NSString *)clientID + clientSecret:(NSString *)clientSecret + source:(MagicLinkSource)source + wpcomScheme:(NSString *)scheme + success:(void (^)(void))success + failure:(void (^)(NSError *error))failure +{ + [self requestWPComAuthLinkForEmail:email + clientID:clientID + clientSecret:clientSecret + source:source + wpcomScheme:scheme + createAccountIfNotFound:NO + success:success + failure:failure]; +} + - (void)requestWPComSignupLinkForEmail:(NSString *)email clientID:(NSString *)clientID clientSecret:(NSString *)clientSecret From 5dcbdabf0f19849925648c6febe8c83d9e3cf8ca Mon Sep 17 00:00:00 2001 From: "Tanner W. Stokes" Date: Wed, 20 Nov 2024 09:37:26 -0500 Subject: [PATCH 93/97] Update changelog. --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e2a6cb28..2cf72d4f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,6 +48,16 @@ _None._ _None._ +## 17.3.0 + +### New Features +- Add upgradeURL to JetpackAssistantFeatureDetails +- Add support for sending magic links to inexistent accounts + +### Internal Changes +- Bump rexml from 3.2.6 to 3.3.9 +- [Tooling] SwiftLint: Use `linter` agent instead of `default` agent + ## 17.2.0 ### New Features From 46f82f8d01a35287cc889cb5740ed55269a0d991 Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Thu, 21 Nov 2024 15:55:18 +1100 Subject: [PATCH 94/97] Add PR numbers to public features in changelog --- CHANGELOG.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2cf72d4f..f843a453 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -51,8 +51,9 @@ _None._ ## 17.3.0 ### New Features -- Add upgradeURL to JetpackAssistantFeatureDetails -- Add support for sending magic links to inexistent accounts + +- Add `upgradeURL` to `JetpackAssistantFeatureDetails` (#822) +- Add support for sending magic links to nonexistent accounts (#812) ### Internal Changes - Bump rexml from 3.2.6 to 3.3.9 From 644bbf674dcac044c9ce3cc6948ae23cca8a3b1f Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Thu, 21 Nov 2024 16:09:22 +1100 Subject: [PATCH 95/97] Update CocoaPods from 1.15.2 to 1.16.2 This is an attempt to address the 500 error we got from the API when trying to publish version 17.3.0. See https://buildkite.com/automattic/wordpresskit-ios/builds/1908#01934d17-d6b4-43c7-9005-0fcb799f5222 --- Gemfile.lock | 44 ++++++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index fbfd2964..abac284d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -5,18 +5,20 @@ GEM base64 nkf rexml - activesupport (7.1.3.2) + activesupport (7.2.2) base64 + benchmark (>= 0.3) bigdecimal - concurrent-ruby (~> 1.0, >= 1.0.2) + concurrent-ruby (~> 1.0, >= 1.3.1) connection_pool (>= 2.2.5) drb i18n (>= 1.6, < 2) + logger (>= 1.4.2) minitest (>= 5.1) - mutex_m - tzinfo (~> 2.0) - addressable (2.8.6) - public_suffix (>= 2.0.2, < 6.0) + securerandom (>= 0.3) + tzinfo (~> 2.0, >= 2.0.5) + addressable (2.8.7) + public_suffix (>= 2.0.2, < 7.0) algoliasearch (1.27.5) httpclient (~> 2.8, >= 2.8.3) json (>= 1.5.1) @@ -41,16 +43,17 @@ GEM aws-eventstream (~> 1, >= 1.0.2) babosa (1.0.4) base64 (0.2.0) - bigdecimal (3.1.7) + benchmark (0.4.0) + bigdecimal (3.1.8) claide (1.1.0) claide-plugins (0.9.2) cork nap open4 (~> 1.3) - cocoapods (1.15.2) + cocoapods (1.16.2) addressable (~> 2.8) claide (>= 1.0.2, < 2.0) - cocoapods-core (= 1.15.2) + cocoapods-core (= 1.16.2) cocoapods-deintegrate (>= 1.0.3, < 2.0) cocoapods-downloader (>= 2.1, < 3.0) cocoapods-plugins (>= 1.0.0, < 2.0) @@ -64,10 +67,10 @@ GEM molinillo (~> 0.8.0) nap (~> 1.0) ruby-macho (>= 2.3.0, < 3.0) - xcodeproj (>= 1.23.0, < 2.0) + xcodeproj (>= 1.27.0, < 2.0) cocoapods-check (1.1.0) cocoapods (~> 1.0) - cocoapods-core (1.15.2) + cocoapods-core (1.16.2) activesupport (>= 5.0, < 8) addressable (~> 2.8) algoliasearch (~> 1.0) @@ -90,7 +93,7 @@ GEM colored2 (3.1.2) commander (4.6.0) highline (~> 2.0.0) - concurrent-ruby (1.2.3) + concurrent-ruby (1.3.4) connection_pool (2.4.1) cork (0.3.0) colored2 (~> 3.1) @@ -212,7 +215,7 @@ GEM xcodeproj (>= 1.13.0, < 2.0.0) xcpretty (~> 0.3.0) xcpretty-travis-formatter (>= 0.0.3) - ffi (1.16.3) + ffi (1.17.0) fourflusher (2.3.1) fuzzy_match (2.0.4) gh_inspector (1.1.3) @@ -261,10 +264,10 @@ GEM http-cookie (1.0.5) domain_name (~> 0.5) httpclient (2.8.3) - i18n (1.14.4) + i18n (1.14.6) concurrent-ruby (~> 1.0) jmespath (1.6.2) - json (2.7.1) + json (2.8.2) jwt (2.8.1) base64 kramdown (2.4.0) @@ -272,14 +275,14 @@ GEM kramdown-parser-gfm (1.1.0) kramdown (~> 2.0) language_server-protocol (3.17.0.3) + logger (1.6.1) mini_magick (4.12.0) mini_mime (1.1.5) - minitest (5.22.3) + minitest (5.25.1) molinillo (0.8.0) multi_json (1.15.0) multipart-post (2.4.0) - mutex_m (0.2.0) - nanaimo (0.3.0) + nanaimo (0.4.0) nap (1.1.0) naturally (2.2.1) netrc (0.11.0) @@ -331,6 +334,7 @@ GEM sawyer (0.9.2) addressable (>= 2.3.5) faraday (>= 0.17.3, < 3) + securerandom (0.3.2) security (0.1.3) signet (0.19.0) addressable (~> 2.8) @@ -356,12 +360,12 @@ GEM uber (0.1.0) unicode-display_width (2.5.0) word_wrap (1.0.0) - xcodeproj (1.25.1) + xcodeproj (1.27.0) CFPropertyList (>= 2.3.3, < 4.0) atomos (~> 0.1.3) claide (>= 1.0.2, < 2.0) colored2 (~> 3.1) - nanaimo (~> 0.3.0) + nanaimo (~> 0.4.0) rexml (>= 3.3.6, < 4.0) xcpretty (0.3.0) rouge (~> 2.0.7) From 44eacfb2e283dcd8f0cfad3edb0d37f48e7f5f8e Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Thu, 19 Jun 2025 14:43:25 +1000 Subject: [PATCH 96/97] Update README with XCFramework deployment instructions --- README.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/README.md b/README.md index b2d11daf..2932a982 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,23 @@ # WordPressKit for iOS + +> [!CAUTION] +> This library is no longer fit for external contribution and community usage. +> +> [WordPress iOS](https://github.com/wordpress-mobile/WordPress-iOS) is its only consumer. +> The repo exists standalone rather than as part of the WordPress codebase because it's convenient to fetch this lump of code that rarely changes as a binary XCFramework dependency. +> See [#816](https://github.com/wordpress-mobile/WordPressKit-iOS/pull/816). + +## XCFramework release instructions + +- Run `.buildkite/create-xcframeworks.sh` to create binaries +- Upload `.build/xcframeworks/WordPressKit.zip` to this repo +- Update binary target in `Package.swift` with a new URL and checksum* +- Push the new changes to your branch +- After testing is done, merge changes into `trunk` + +*_checksum is echoed at the end of the `create-xcframeworks.sh` script_ + ## About WordPressKit offers a clean and simple WordPress.com and WordPress.org API. From 62938ce27e9e4f971ae726f8015ad754f71a0928 Mon Sep 17 00:00:00 2001 From: Gio Lodi Date: Thu, 19 Jun 2025 15:47:33 +1000 Subject: [PATCH 97/97] =?UTF-8?q?Remove=20CI=20steps=20for=20CocoaPods=20?= =?UTF-8?q?=E2=80=93=20We=20no=20longer=20publish=20to=20CocoaPods?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .buildkite/pipeline.yml | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml index 452b97f6..09d1a91e 100644 --- a/.buildkite/pipeline.yml +++ b/.buildkite/pipeline.yml @@ -39,22 +39,3 @@ steps: context: SwiftLint agents: queue: linter - - - label: "🧹 Lint" - key: "lint" - command: | - lint_pod - plugins: *common_plugins - - ################# - # Publish the Podspec (if we're building a tag) - ################# - - label: "⬆️ Publish Podspec" - key: "publish" - command: .buildkite/publish-pod.sh - plugins: *common_plugins - depends_on: - - "test" - - "validate" - - "lint" - if: build.tag != null