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

Commit e8e8652

Browse files
committed
Add getSubsciberDetails
1 parent 5ecc194 commit e8e8652

File tree

6 files changed

+113
-32
lines changed

6 files changed

+113
-32
lines changed

Package.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ let package = Package(
1111
targets: [
1212
.binaryTarget(
1313
name: "WordPressKit",
14-
url: "https://github.com/user-attachments/files/20067014/WordPressKit.zip",
15-
checksum: "e20c387a1c32306e502326af03f46629140b9d1bc994de3c614890a0fd24b690"
14+
url: "https://github.com/user-attachments/files/20087743/WordPressKit.zip",
15+
checksum: "138689853d7a65384fa5dae5b5732b40769689a0108f4265e23cc47ca3eea647"
1616
),
1717
]
1818
)

Sources/WordPressKit/Models/RemoteSubscriber.swift

Lines changed: 0 additions & 23 deletions
This file was deleted.

Sources/WordPressKit/Services/SubscribersServiceRemote.swift

Lines changed: 80 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import Foundation
22

33
public class SubscribersServiceRemote: ServiceRemoteWordPressComREST {
44

5-
// MARK: GET
5+
// MARK: GET Subscribers (Paginated List)
66

77
public struct GetSubscribersParameters: Hashable {
88
public var sortField: SortField?
@@ -51,7 +51,29 @@ public class SubscribersServiceRemote: ServiceRemoteWordPressComREST {
5151
public var total: Int
5252
public var pages: Int
5353
public var page: Int
54-
public var subscribers: [RemoteSubscriber]
54+
public var subscribers: [Subscriber]
55+
56+
public struct Subscriber: Decodable {
57+
public let subscriberID: Int
58+
public let dotComUserID: Int
59+
public let displayName: String?
60+
public let avatar: String?
61+
public let emailAddress: String?
62+
public let dateSubscribed: Date
63+
public let isEmailSubscriptionEnabled: Bool
64+
public let subscriptionStatus: String?
65+
66+
private enum CodingKeys: String, CodingKey {
67+
case subscriberID = "subscription_id"
68+
case dotComUserID = "user_id"
69+
case displayName = "display_name"
70+
case emailAddress = "email_address"
71+
case avatar
72+
case dateSubscribed = "date_subscribed"
73+
case isEmailSubscriptionEnabled = "is_email_subscriber"
74+
case subscriptionStatus = "subscription_status"
75+
}
76+
}
5577
}
5678

5779
/// Gets the list of the site subscribers, including WordPress.com users and
@@ -96,6 +118,61 @@ public class SubscribersServiceRemote: ServiceRemoteWordPressComREST {
96118
).get().body
97119
}
98120

121+
// MARK: GET Subscriber (Individual Details)
122+
123+
public struct GetSubscriberDetailsResponse: Decodable {
124+
public let subscriberID: Int
125+
public let dotComUserID: Int
126+
public let displayName: String?
127+
public let avatar: String?
128+
public let emailAddress: String?
129+
public let dateSubscribed: Date
130+
public let isEmailSubscriptionEnabled: Bool
131+
public let subscriptionStatus: String?
132+
public let country: Country?
133+
134+
public struct Country: Decodable {
135+
public var code: String?
136+
public var name: String?
137+
}
138+
139+
private enum CodingKeys: String, CodingKey {
140+
case subscriberID = "subscription_id"
141+
case dotComUserID = "user_id"
142+
case displayName = "display_name"
143+
case emailAddress = "email_address"
144+
case avatar
145+
case dateSubscribed = "date_subscribed"
146+
case isEmailSubscriptionEnabled = "is_email_subscriber"
147+
case subscriptionStatus = "subscription_status"
148+
case country
149+
}
150+
}
151+
152+
/// Gets stats for the given subscriber.
153+
///
154+
/// Example: https://public-api.wordpress.com/wpcom/v2/sites/239619264/subscribers/individual?subscription_id=907116368
155+
public func getSubsciberDetails(
156+
siteID: Int,
157+
subscriberID: Int
158+
) async throws -> GetSubscriberDetailsResponse {
159+
let url = self.path(forEndpoint: "sites/\(siteID)/subscribers/individual", withVersion: ._2_0)
160+
let query: [String: Any] = [
161+
"subscription_id": subscriberID
162+
]
163+
164+
let decoder = JSONDecoder()
165+
decoder.dateDecodingStrategy = JSONDecoder.DateDecodingStrategy.supportMultipleDateFormats
166+
167+
return try await wordPressComRestApi.perform(
168+
.get,
169+
URLString: url,
170+
parameters: query,
171+
jsonDecoder: decoder,
172+
type: GetSubscriberDetailsResponse.self
173+
).get().body
174+
}
175+
99176
public struct GetSubscriberStatsResponse: Decodable {
100177
public var emailsSent: Int
101178
public var uniqueOpens: Int
@@ -111,7 +188,7 @@ public class SubscribersServiceRemote: ServiceRemoteWordPressComREST {
111188
) async throws -> GetSubscriberStatsResponse {
112189
let url = self.path(forEndpoint: "sites/\(siteID)/individual-subscriber-stats", withVersion: ._2_0)
113190
let query: [String: Any] = [
114-
"subscription_id": 907116368
191+
"subscription_id": subscriberID
115192
]
116193
return try await wordPressComRestApi.perform(
117194
.get,
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"user_id": 255064965,
3+
"subscription_id": 907116368,
4+
"email_address": "[email protected]",
5+
"date_subscribed": "2025-04-17T14:40:00+00:00",
6+
"is_email_subscriber": false,
7+
"subscription_status": "Subscribed",
8+
"avatar": "https://0.gravatar.com/avatar/694664524f7d391c4425ab07627f4e44e970f597985d24ce3dc4c27173316c20?s=128&d=https%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D128&r=G",
9+
"display_name": "Alex",
10+
"url": "http://test841027.wordpress.com",
11+
"country": {
12+
"code": "US",
13+
"name": "United States"
14+
}
15+
}

Tests/WordPressKitTests/Tests/SubscribersServiceRemoteTests.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,18 @@ class SubscribersServiceRemoteTests: RemoteTestCase, RESTTestable {
1717
XCTAssertEqual(subscriber.dotComUserID, 1)
1818
}
1919

20+
func testDecoderSubscriberDetailsResponse() throws {
21+
let data = try JSONLoader.data(named: "site-subscriber-get-details-response")
22+
23+
let decoder = JSONDecoder()
24+
decoder.dateDecodingStrategy = JSONDecoder.DateDecodingStrategy.supportMultipleDateFormats
25+
26+
let response = try decoder.decode(SubscribersServiceRemote.GetSubscriberDetailsResponse.self, from: data)
27+
28+
XCTAssertEqual(response.country?.code, "US")
29+
XCTAssertEqual(response.country?.name, "United States")
30+
}
31+
2032
func testDecoderSubscriberStatsResponse() throws {
2133
let data = try JSONLoader.data(named: "site-subscriber-stats-response")
2234

WordPressKit.xcodeproj/project.pbxproj

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@
5454
0CE311BD2DCBB52C003AADB3 /* SubscribersServiceRemote.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CE311BC2DCBB52C003AADB3 /* SubscribersServiceRemote.swift */; };
5555
0CE311BF2DCBB588003AADB3 /* SubscribersServiceRemoteTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CE311BE2DCBB588003AADB3 /* SubscribersServiceRemoteTests.swift */; };
5656
0CE311C52DCBB970003AADB3 /* site-subscriber-stats-response.json in Resources */ = {isa = PBXBuildFile; fileRef = 0CE311C42DCBB970003AADB3 /* site-subscriber-stats-response.json */; };
57-
0CE4E8252DC027AC00056DD9 /* RemoteSubscriber.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CE4E8242DC027AC00056DD9 /* RemoteSubscriber.swift */; };
57+
0CE311C72DCBBA01003AADB3 /* site-subscriber-get-details-response.json in Resources */ = {isa = PBXBuildFile; fileRef = 0CE311C62DCBBA01003AADB3 /* site-subscriber-get-details-response.json */; };
5858
0CED1FE82B617CF300E6DD52 /* AtomicSiteServiceRemote.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CED1FE72B617CF300E6DD52 /* AtomicSiteServiceRemote.swift */; };
5959
0CED1FEB2B617D7D00E6DD52 /* AtomicLogs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CED1FEA2B617D7D00E6DD52 /* AtomicLogs.swift */; };
6060
1769DEAA24729AFF00F42EFC /* HomepageSettingsServiceRemote.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1769DEA924729AFF00F42EFC /* HomepageSettingsServiceRemote.swift */; };
@@ -833,7 +833,7 @@
833833
0CE311BC2DCBB52C003AADB3 /* SubscribersServiceRemote.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscribersServiceRemote.swift; sourceTree = "<group>"; };
834834
0CE311BE2DCBB588003AADB3 /* SubscribersServiceRemoteTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscribersServiceRemoteTests.swift; sourceTree = "<group>"; };
835835
0CE311C42DCBB970003AADB3 /* site-subscriber-stats-response.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "site-subscriber-stats-response.json"; sourceTree = "<group>"; };
836-
0CE4E8242DC027AC00056DD9 /* RemoteSubscriber.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteSubscriber.swift; sourceTree = "<group>"; };
836+
0CE311C62DCBBA01003AADB3 /* site-subscriber-get-details-response.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "site-subscriber-get-details-response.json"; sourceTree = "<group>"; };
837837
0CED1FE72B617CF300E6DD52 /* AtomicSiteServiceRemote.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AtomicSiteServiceRemote.swift; sourceTree = "<group>"; };
838838
0CED1FEA2B617D7D00E6DD52 /* AtomicLogs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AtomicLogs.swift; sourceTree = "<group>"; };
839839
1769DEA924729AFF00F42EFC /* HomepageSettingsServiceRemote.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomepageSettingsServiceRemote.swift; sourceTree = "<group>"; };
@@ -1876,7 +1876,6 @@
18761876
4A68E3DC294070A7004AC3DC /* RemoteReaderSite.swift */,
18771877
4A68E3E0294076C1004AC3DC /* RemoteReaderSiteInfo.swift */,
18781878
9F3E0B9A208732B2009CB5BA /* RemoteReaderSiteInfoSubscription.swift */,
1879-
0CE4E8242DC027AC00056DD9 /* RemoteSubscriber.swift */,
18801879
4A68E3DE29407100004AC3DC /* RemoteReaderTopic.swift */,
18811880
74E2295D1F1E777B0085F7F2 /* RemoteSharingButton.swift */,
18821881
7430C9C81F192F260051B8E6 /* RemoteSourcePostAttribution.h */,
@@ -2556,6 +2555,7 @@
25562555
74D67F0D1F15C2D70010C5ED /* site-roles-bad-json-failure.json */,
25572556
0C8069A62DC03E85008DFC2F /* site-subscribers-response.json */,
25582557
0CE311C42DCBB970003AADB3 /* site-subscriber-stats-response.json */,
2558+
0CE311C62DCBBA01003AADB3 /* site-subscriber-get-details-response.json */,
25592559
74D67F0E1F15C2D70010C5ED /* site-roles-success.json */,
25602560
D8DB404121EF22B500B8238E /* site-segments-multiple.json */,
25612561
D813437721F6D7DC0060D99A /* site-segments-single.json */,
@@ -3157,6 +3157,7 @@
31573157
B04D8C052BB7895A002717A2 /* stats-insight-followers.json in Resources */,
31583158
74D67F3B1F15C3740010C5ED /* site-viewers-delete-success.json in Resources */,
31593159
93BD275F1EE73442002BB00B /* me-sites-auth-failure.json in Resources */,
3160+
0CE311C72DCBBA01003AADB3 /* site-subscriber-get-details-response.json in Resources */,
31603161
74585BA11F0D6F5300E7E667 /* domain-service-empty.json in Resources */,
31613162
74C473C51EF33242009918F2 /* site-active-purchases-two-active-success.json in Resources */,
31623163
4A3239682B74319400EFD2A8 /* self-hosted-plugins-install.json in Resources */,
@@ -3509,7 +3510,6 @@
35093510
3FD634F32BC3AD6200CEDF5E /* Result+Callback.swift in Sources */,
35103511
B5A4822E20AC6C1A009D95F6 /* WPKitLogging.m in Sources */,
35113512
3FE2E97C2BC3A332002CA2E1 /* WordPressComRestApi.swift in Sources */,
3512-
0CE4E8252DC027AC00056DD9 /* RemoteSubscriber.swift in Sources */,
35133513
FE6C673C2BB739950083ECAB /* NSAttributedString+extensions.swift in Sources */,
35143514
7430C9A61F1927180051B8E6 /* ReaderSiteServiceRemote.m in Sources */,
35153515
FEE4EF57272FDD4B003CDA3C /* RemoteCommentV2.swift in Sources */,

0 commit comments

Comments
 (0)