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

Commit 77aee91

Browse files
author
Paul Von Schrottky
authored
Add endpoint for fetching subscriber history (#795)
2 parents 14aa53a + 7f47dbc commit 77aee91

File tree

6 files changed

+1044
-1
lines changed

6 files changed

+1044
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ _None._
3737
- Add `getPost(withID)` to `PostServiceRemoteExtended` [#785]
3838
- Add support for metadata to `PostServiceRemoteExtended` [#783]
3939
- Add fetching of `StatsEmailsSummaryData` to `StatsService` [#794]
40+
- Add fetching of `StatsSubscribersSummaryData` to `StatsService` [#795]
4041

4142
### Bug Fixes
4243

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import Foundation
2+
import WordPressShared
3+
4+
public struct StatsSubscribersSummaryData: Equatable {
5+
public let history: [SubscriberData]
6+
public let period: StatsPeriodUnit
7+
public let periodEndDate: Date
8+
9+
public init(history: [SubscriberData], period: StatsPeriodUnit, periodEndDate: Date) {
10+
self.history = history
11+
self.period = period
12+
self.periodEndDate = periodEndDate
13+
}
14+
}
15+
16+
extension StatsSubscribersSummaryData: StatsTimeIntervalData {
17+
public static var pathComponent: String {
18+
return "stats/subscribers"
19+
}
20+
21+
static var dateFormatter: DateFormatter = {
22+
let df = DateFormatter()
23+
df.locale = Locale(identifier: "en_US_POS")
24+
df.dateFormat = "yyyy-MM-dd"
25+
return df
26+
}()
27+
28+
static var weeksDateFormatter: DateFormatter = {
29+
let df = DateFormatter()
30+
df.locale = Locale(identifier: "en_US_POS")
31+
df.dateFormat = "yyyy'W'MM'W'dd"
32+
return df
33+
}()
34+
35+
public struct SubscriberData: Equatable {
36+
public let date: Date
37+
public let count: Int
38+
39+
public init(date: Date, count: Int) {
40+
self.date = date
41+
self.count = count
42+
}
43+
}
44+
45+
public init?(date: Date, period: StatsPeriodUnit, jsonDictionary: [String: AnyObject]) {
46+
guard
47+
let fields = jsonDictionary["fields"] as? [String],
48+
let data = jsonDictionary["data"] as? [[Any]],
49+
let dateIndex = fields.firstIndex(of: "period"),
50+
let countIndex = fields.firstIndex(of: "subscribers")
51+
else {
52+
return nil
53+
}
54+
55+
let history: [SubscriberData?] = data.map { elements in
56+
guard elements.indices.contains(dateIndex) && elements.indices.contains(countIndex),
57+
let dateString = elements[dateIndex] as? String,
58+
let date = StatsSubscribersSummaryData.parsedDate(from: dateString, for: period)
59+
else {
60+
return nil
61+
}
62+
63+
let count = elements[countIndex] as? Int ?? 0
64+
65+
return SubscriberData(date: date, count: count)
66+
}
67+
68+
let sorted = history.compactMap { $0 }.sorted { $0.date < $1.date }
69+
70+
self = .init(history: sorted, period: period, periodEndDate: date)
71+
}
72+
73+
private static func parsedDate(from dateString: String, for period: StatsPeriodUnit) -> Date? {
74+
switch period {
75+
case .week:
76+
return self.weeksDateFormatter.date(from: dateString)
77+
case .day, .month, .year:
78+
return self.dateFormatter.date(from: dateString)
79+
}
80+
}
81+
82+
public static func queryProperties(with date: Date, period: StatsPeriodUnit, maxCount: Int) -> [String: String] {
83+
return ["quantity": String(maxCount), "unit": period.stringValue]
84+
}
85+
}

Sources/WordPressKit/Services/StatsServiceRemoteV2.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,7 @@ extension StatsTimeIntervalData {
395395

396396
// We'll bring `StatsPeriodUnit` into this file when the "old" `WPStatsServiceRemote` gets removed.
397397
// For now we can piggy-back off the old type and add this as an extension.
398-
extension StatsPeriodUnit {
398+
public extension StatsPeriodUnit {
399399
var stringValue: String {
400400
switch self {
401401
case .day:

0 commit comments

Comments
 (0)