Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for v2/sites/site_id/subscribers endpoint #800

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions Sources/WordPressKit/Models/Subscriber.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import Foundation

struct SubscribersData: Codable {
let total: Int
let pages: Int
let page: Int
let perPage: Int
let subscribers: [SiteSubscriber]

enum CodingKeys: String, CodingKey {
case total
case pages
case page
case perPage = "per_page"
case subscribers
}
}

public struct SiteSubscriber: Codable {
public let userID: Int
public let subscriptionID: Int
public let emailAddress: String
public let dateSubscribed: Date
public let avatarUrl: URL?
public let displayName: String
public let url: String?

private enum CodingKeys: String, CodingKey {
case userID = "user_id"
case subscriptionID = "subscription_id"
case emailAddress = "email_address"
case dateSubscribed = "date_subscribed"
case avatarUrl = "avatar"
case displayName = "display_name"
case url
}

public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.userID = try container.decode(Int.self, forKey: .userID)
self.subscriptionID = try container.decode(Int.self, forKey: .subscriptionID)
self.emailAddress = try container.decode(String.self, forKey: .emailAddress)
self.avatarUrl = try? container.decodeIfPresent(URL.self, forKey: .avatarUrl)
self.displayName = try container.decode(String.self, forKey: .displayName)
self.url = try? container.decodeIfPresent(String.self, forKey: .url)

let dateString = try container.decode(String.self, forKey: .dateSubscribed)
if let date = ISO8601DateFormatter().date(from: dateString) {
self.dateSubscribed = date
} else {
throw DecodingError.dataCorruptedError(forKey: .dateSubscribed, in: container, debugDescription: "Date string does not match format expected by formatter.")
}
}
}
48 changes: 48 additions & 0 deletions Sources/WordPressKit/Services/PeopleServiceRemote.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ public class PeopleServiceRemote: ServiceRemoteWordPressComREST {
}

/// Retrieves the collection of Followers associated to a site.
/// This is a legacy endpoint. Prefer using v2/sites/{site_id}/subscribers instead
///
/// - Parameters:
/// - siteID: The target site's ID.
Expand Down Expand Up @@ -97,6 +98,53 @@ public class PeopleServiceRemote: ServiceRemoteWordPressComREST {
})
}

/// Retrieves the collection of Subscribers associated to a site.
///
/// - Parameters:
/// - siteID: The target site's ID.
/// - count: The first N followers to be skipped in the returned array.
/// - size: Number of objects to retrieve.
/// - success: Closure to be executed on success
/// - failure: Closure to be executed on error.
///
/// - Returns: An array of Subscribers.
///
public func getSubscribers(
_ siteID: Int,
offset: Int = 0,
count: Int,
success: @escaping ((_ subscribers: [SiteSubscriber], _ hasMore: Bool) -> Void),
failure: @escaping (Error) -> Void
) {
let endpoint = "sites/\(siteID)/subscribers"
let path = self.path(forEndpoint: endpoint, withVersion: ._2_0)
let pageNumber = (offset / count + 1)
let parameters: [String: AnyObject] = [
"per_page": count as AnyObject,
"page": pageNumber as AnyObject
]

wordPressComRESTAPI.get(path, parameters: parameters, success: { (responseObject, _) in
guard let response = responseObject as? [String: AnyObject] else {
failure(ResponseError.decodingFailure)
return
}

do {
let jsonData = try JSONSerialization.data(withJSONObject: response, options: [])
let decoder = JSONDecoder()
let subscribersData = try decoder.decode(SubscribersData.self, from: jsonData)
let hasMore = subscribersData.total > (offset + subscribersData.subscribers.count)
success(subscribersData.subscribers, hasMore)
} catch {
failure(ResponseError.decodingFailure)
return
}
}, failure: { (error, _) in
failure(error)
})
}

/// Retrieves the collection of email followers associated to a site.
///
/// - Parameters:
Expand Down
16 changes: 16 additions & 0 deletions WordPressKit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
01438D392B6A361B0097D60A /* stats-summary.json in Resources */ = {isa = PBXBuildFile; fileRef = 01438D372B6A35FB0097D60A /* stats-summary.json */; };
01438D3B2B6A36BF0097D60A /* StatsTotalsSummaryData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01438D3A2B6A36BF0097D60A /* StatsTotalsSummaryData.swift */; };
0152100C28EDA9E400DD6783 /* StatsAnnualAndMostPopularTimeInsightDecodingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0152100B28EDA9E400DD6783 /* StatsAnnualAndMostPopularTimeInsightDecodingTests.swift */; };
019A800B2BE365880012DBE0 /* SubscriberTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 019A800A2BE365880012DBE0 /* SubscriberTests.swift */; };
019A800D2BE367F70012DBE0 /* Subscriber.swift in Sources */ = {isa = PBXBuildFile; fileRef = 019A800C2BE367F70012DBE0 /* Subscriber.swift */; };
019C5B8B2BD59CE000A69DB0 /* StatsEmailsSummaryData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 019C5B892BD59CE000A69DB0 /* StatsEmailsSummaryData.swift */; };
0847B92C2A4442730044D32F /* IPLocationRemote.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0847B92B2A4442730044D32F /* IPLocationRemote.swift */; };
08C7493E2A45EA11000DA0E2 /* IPLocationRemoteTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 08C7493D2A45EA11000DA0E2 /* IPLocationRemoteTests.swift */; };
Expand Down Expand Up @@ -766,6 +768,8 @@
01438D372B6A35FB0097D60A /* stats-summary.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "stats-summary.json"; sourceTree = "<group>"; };
01438D3A2B6A36BF0097D60A /* StatsTotalsSummaryData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatsTotalsSummaryData.swift; sourceTree = "<group>"; };
0152100B28EDA9E400DD6783 /* StatsAnnualAndMostPopularTimeInsightDecodingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatsAnnualAndMostPopularTimeInsightDecodingTests.swift; sourceTree = "<group>"; };
019A800A2BE365880012DBE0 /* SubscriberTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscriberTests.swift; sourceTree = "<group>"; };
019A800C2BE367F70012DBE0 /* Subscriber.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Subscriber.swift; sourceTree = "<group>"; };
019C5B892BD59CE000A69DB0 /* StatsEmailsSummaryData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatsEmailsSummaryData.swift; sourceTree = "<group>"; };
0847B92B2A4442730044D32F /* IPLocationRemote.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IPLocationRemote.swift; sourceTree = "<group>"; };
08C7493D2A45EA11000DA0E2 /* IPLocationRemoteTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IPLocationRemoteTests.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1542,6 +1546,14 @@
path = TimeInterval;
sourceTree = "<group>";
};
019A80092BE365790012DBE0 /* Subscribers */ = {
isa = PBXGroup;
children = (
019A800A2BE365880012DBE0 /* SubscriberTests.swift */,
);
path = Subscribers;
sourceTree = "<group>";
};
019C5B882BD59C7800A69DB0 /* Emails */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -1826,6 +1838,7 @@
FE20A6A3282A96C00025E975 /* RemoteBloggingPromptsSettings.swift */,
1DAC3D2529AF4F250068FE13 /* RemoteVideoPressVideo.swift */,
F41D98E92B48602B004EC050 /* SessionDetails.swift */,
019A800C2BE367F70012DBE0 /* Subscriber.swift */,
);
path = Models;
sourceTree = "<group>";
Expand Down Expand Up @@ -2618,6 +2631,7 @@
F3FF8A1A279C86AF00E5C90F /* Models */ = {
isa = PBXGroup;
children = (
019A80092BE365790012DBE0 /* Subscribers */,
F3FF8A1B279C86E000E5C90F /* Stats */,
F3FF8A20279C8EE200E5C90F /* RemotePersonTests.swift */,
1DC837C129B9F04F009DCD4B /* RemoteVideoPressVideoTests.swift */,
Expand Down Expand Up @@ -3469,6 +3483,7 @@
82FFBF501F45EFD100F4573F /* RemoteBlogJetpackSettings.swift in Sources */,
74650F741F0EA1E200188EDB /* RemoteGravatarProfile.swift in Sources */,
40E7FEB4221063480032834E /* StatsTodayInsight.swift in Sources */,
019A800D2BE367F70012DBE0 /* Subscriber.swift in Sources */,
3FE2E94F2BB29A1B002CA2E1 /* FilePart.m in Sources */,
F41D98EA2B48602B004EC050 /* SessionDetails.swift in Sources */,
436D563C2118E18D00CEAA33 /* WPState.swift in Sources */,
Expand Down Expand Up @@ -3573,6 +3588,7 @@
93F50A3A1F226BB600B5BEBA /* WordPressComServiceRemoteRestTests.swift in Sources */,
E13EE14C1F332C4400C15787 /* PluginServiceRemoteTests.swift in Sources */,
736C971021E80D48007A4200 /* SiteVerticalsPromptResponseDecodingTests.swift in Sources */,
019A800B2BE365880012DBE0 /* SubscriberTests.swift in Sources */,
74B335D81F06F1CA0053A184 /* MockWordPressComRestApi.swift in Sources */,
08C7493E2A45EA11000DA0E2 /* IPLocationRemoteTests.swift in Sources */,
32AF21E3236DEB3C001C6502 /* PostServiceRemoteRESTAutosaveTests.swift in Sources */,
Expand Down