diff --git a/CHANGELOG.md b/CHANGELOG.md index d021365d..fb7976cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,7 @@ _None._ - Add `getPost(withID)` to `PostServiceRemoteExtended` [#785] - Add support for metadata to `PostServiceRemoteExtended` [#783] - Add fetching of `StatsEmailsSummaryData` to `StatsService` [#794] +- Add fetching of `StatsSubscribersSummaryData` to `StatsService` [#795] ### Bug Fixes diff --git a/Sources/WordPressKit/Models/Stats/StatsSubscribersSummaryData.swift b/Sources/WordPressKit/Models/Stats/StatsSubscribersSummaryData.swift new file mode 100644 index 00000000..5ed9ee16 --- /dev/null +++ b/Sources/WordPressKit/Models/Stats/StatsSubscribersSummaryData.swift @@ -0,0 +1,85 @@ +import Foundation +import WordPressShared + +public struct StatsSubscribersSummaryData: Equatable { + public let history: [SubscriberData] + public let period: StatsPeriodUnit + public let periodEndDate: Date + + public init(history: [SubscriberData], period: StatsPeriodUnit, periodEndDate: Date) { + self.history = history + self.period = period + self.periodEndDate = periodEndDate + } +} + +extension StatsSubscribersSummaryData: StatsTimeIntervalData { + public static var pathComponent: String { + return "stats/subscribers" + } + + static var dateFormatter: DateFormatter = { + let df = DateFormatter() + df.locale = Locale(identifier: "en_US_POS") + df.dateFormat = "yyyy-MM-dd" + return df + }() + + static var weeksDateFormatter: DateFormatter = { + let df = DateFormatter() + df.locale = Locale(identifier: "en_US_POS") + df.dateFormat = "yyyy'W'MM'W'dd" + return df + }() + + public struct SubscriberData: Equatable { + public let date: Date + public let count: Int + + public init(date: Date, count: Int) { + self.date = date + self.count = count + } + } + + public init?(date: Date, period: StatsPeriodUnit, jsonDictionary: [String: AnyObject]) { + guard + let fields = jsonDictionary["fields"] as? [String], + let data = jsonDictionary["data"] as? [[Any]], + let dateIndex = fields.firstIndex(of: "period"), + let countIndex = fields.firstIndex(of: "subscribers") + else { + return nil + } + + let history: [SubscriberData?] = data.map { elements in + guard elements.indices.contains(dateIndex) && elements.indices.contains(countIndex), + let dateString = elements[dateIndex] as? String, + let date = StatsSubscribersSummaryData.parsedDate(from: dateString, for: period) + else { + return nil + } + + let count = elements[countIndex] as? Int ?? 0 + + return SubscriberData(date: date, count: count) + } + + let sorted = history.compactMap { $0 }.sorted { $0.date < $1.date } + + self = .init(history: sorted, period: period, periodEndDate: date) + } + + private static func parsedDate(from dateString: String, for period: StatsPeriodUnit) -> Date? { + switch period { + case .week: + return self.weeksDateFormatter.date(from: dateString) + case .day, .month, .year: + return self.dateFormatter.date(from: dateString) + } + } + + public static func queryProperties(with date: Date, period: StatsPeriodUnit, maxCount: Int) -> [String: String] { + return ["quantity": String(maxCount), "unit": period.stringValue] + } +} diff --git a/Sources/WordPressKit/Services/StatsServiceRemoteV2.swift b/Sources/WordPressKit/Services/StatsServiceRemoteV2.swift index be9d554d..6cf675a6 100644 --- a/Sources/WordPressKit/Services/StatsServiceRemoteV2.swift +++ b/Sources/WordPressKit/Services/StatsServiceRemoteV2.swift @@ -395,7 +395,7 @@ extension StatsTimeIntervalData { // We'll bring `StatsPeriodUnit` into this file when the "old" `WPStatsServiceRemote` gets removed. // For now we can piggy-back off the old type and add this as an extension. -extension StatsPeriodUnit { +public extension StatsPeriodUnit { var stringValue: String { switch self { case .day: diff --git a/Tests/WordPressKitTests/Mock Data/stats-subscribers.json b/Tests/WordPressKitTests/Mock Data/stats-subscribers.json new file mode 100644 index 00000000..803ff7b5 --- /dev/null +++ b/Tests/WordPressKitTests/Mock Data/stats-subscribers.json @@ -0,0 +1,921 @@ +{ + "date": "2024-04-22", + "unit": "day", + "fields": [ + "period", + "subscribers", + "subscribers_change" + ], + "data": [ + [ + "2024-04-22", + 77, + 0, + [ + "2024-04-22" + ] + ], + [ + "2024-04-21", + 78, + 0, + [ + "2024-04-21" + ] + ], + [ + "2024-04-20", + 78, + 0, + [ + "2024-04-20" + ] + ], + [ + "2024-04-19", + 78, + 0, + [ + "2024-04-19" + ] + ], + [ + "2024-04-18", + 78, + 0, + [ + "2024-04-18" + ] + ], + [ + "2024-04-17", + 78, + 0, + [ + "2024-04-17" + ] + ], + [ + "2024-04-16", + 78, + 0, + [ + "2024-04-16" + ] + ], + [ + "2024-04-15", + 78, + 0, + [ + "2024-04-15" + ] + ], + [ + "2024-04-14", + 78, + 0, + [ + "2024-04-14" + ] + ], + [ + "2024-04-13", + 78, + 0, + [ + "2024-04-13" + ] + ], + [ + "2024-04-12", + 78, + 0, + [ + "2024-04-12" + ] + ], + [ + "2024-04-11", + 78, + 0, + [ + "2024-04-11" + ] + ], + [ + "2024-04-10", + 78, + 0, + [ + "2024-04-10" + ] + ], + [ + "2024-04-09", + 78, + 0, + [ + "2024-04-09" + ] + ], + [ + "2024-04-08", + 76, + 0, + [ + "2024-04-08" + ] + ], + [ + "2024-04-07", + 76, + 0, + [ + "2024-04-07" + ] + ], + [ + "2024-04-06", + 76, + 0, + [ + "2024-04-06" + ] + ], + [ + "2024-04-05", + 76, + 0, + [ + "2024-04-05" + ] + ], + [ + "2024-04-04", + 78, + 0, + [ + "2024-04-04" + ] + ], + [ + "2024-04-03", + 78, + 0, + [ + "2024-04-03" + ] + ], + [ + "2024-04-02", + 78, + 0, + [ + "2024-04-02" + ] + ], + [ + "2024-04-01", + 78, + 0, + [ + "2024-04-01" + ] + ], + [ + "2024-03-31", + 78, + 0, + [ + "2024-03-31" + ] + ], + [ + "2024-03-30", + 78, + 0, + [ + "2024-03-30" + ] + ], + [ + "2024-03-29", + 79, + 0, + [ + "2024-03-29" + ] + ], + [ + "2024-03-28", + 79, + 0, + [ + "2024-03-28" + ] + ], + [ + "2024-03-27", + 79, + 0, + [ + "2024-03-27" + ] + ], + [ + "2024-03-26", + 80, + 0, + [ + "2024-03-26" + ] + ], + [ + "2024-03-25", + 78, + 0, + [ + "2024-03-25" + ] + ], + [ + "2024-03-24", + 78, + 0, + [ + "2024-03-24" + ] + ] + ], + "periods": [ + { + "label": "2024-03-24", + "dates": [ + "2024-03-24" + ] + }, + { + "label": "2024-03-25", + "dates": [ + "2024-03-25" + ] + }, + { + "label": "2024-03-26", + "dates": [ + "2024-03-26" + ] + }, + { + "label": "2024-03-27", + "dates": [ + "2024-03-27" + ] + }, + { + "label": "2024-03-28", + "dates": [ + "2024-03-28" + ] + }, + { + "label": "2024-03-29", + "dates": [ + "2024-03-29" + ] + }, + { + "label": "2024-03-30", + "dates": [ + "2024-03-30" + ] + }, + { + "label": "2024-03-31", + "dates": [ + "2024-03-31" + ] + }, + { + "label": "2024-04-01", + "dates": [ + "2024-04-01" + ] + }, + { + "label": "2024-04-02", + "dates": [ + "2024-04-02" + ] + }, + { + "label": "2024-04-03", + "dates": [ + "2024-04-03" + ] + }, + { + "label": "2024-04-04", + "dates": [ + "2024-04-04" + ] + }, + { + "label": "2024-04-05", + "dates": [ + "2024-04-05" + ] + }, + { + "label": "2024-04-06", + "dates": [ + "2024-04-06" + ] + }, + { + "label": "2024-04-07", + "dates": [ + "2024-04-07" + ] + }, + { + "label": "2024-04-08", + "dates": [ + "2024-04-08" + ] + }, + { + "label": "2024-04-09", + "dates": [ + "2024-04-09" + ] + }, + { + "label": "2024-04-10", + "dates": [ + "2024-04-10" + ] + }, + { + "label": "2024-04-11", + "dates": [ + "2024-04-11" + ] + }, + { + "label": "2024-04-12", + "dates": [ + "2024-04-12" + ] + }, + { + "label": "2024-04-13", + "dates": [ + "2024-04-13" + ] + }, + { + "label": "2024-04-14", + "dates": [ + "2024-04-14" + ] + }, + { + "label": "2024-04-15", + "dates": [ + "2024-04-15" + ] + }, + { + "label": "2024-04-16", + "dates": [ + "2024-04-16" + ] + }, + { + "label": "2024-04-17", + "dates": [ + "2024-04-17" + ] + }, + { + "label": "2024-04-18", + "dates": [ + "2024-04-18" + ] + }, + { + "label": "2024-04-19", + "dates": [ + "2024-04-19" + ] + }, + { + "label": "2024-04-20", + "dates": [ + "2024-04-20" + ] + }, + { + "label": "2024-04-21", + "dates": [ + "2024-04-21" + ] + }, + { + "label": "2024-04-22", + "dates": [ + "2024-04-22" + ] + } + ], + "next_date_subscriber_total_before_change": 78, + "all_days": [ + "2024-03-23", + "2024-03-24", + "2024-03-25", + "2024-03-26", + "2024-03-27", + "2024-03-28", + "2024-03-29", + "2024-03-30", + "2024-03-31", + "2024-04-01", + "2024-04-02", + "2024-04-03", + "2024-04-04", + "2024-04-05", + "2024-04-06", + "2024-04-07", + "2024-04-08", + "2024-04-09", + "2024-04-10", + "2024-04-11", + "2024-04-12", + "2024-04-13", + "2024-04-14", + "2024-04-15", + "2024-04-16", + "2024-04-17", + "2024-04-18", + "2024-04-19", + "2024-04-20", + "2024-04-21", + "2024-04-22", + "2024-04-23" + ], + "utc_all_dates_subscriber_total_before_change": { + "2024-04-23": null, + "2024-04-22": 77, + "2024-04-21": 78, + "2024-04-20": 78, + "2024-04-19": 78, + "2024-04-18": 78, + "2024-04-17": 78, + "2024-04-16": 78, + "2024-04-15": 78, + "2024-04-14": 78, + "2024-04-13": 78, + "2024-04-12": 78, + "2024-04-11": 78, + "2024-04-10": 78, + "2024-04-09": 76, + "2024-04-08": 76, + "2024-04-07": 76, + "2024-04-06": 76, + "2024-04-05": 76, + "2024-04-04": 78, + "2024-04-03": 78, + "2024-04-02": 78, + "2024-04-01": 78, + "2024-03-31": 78, + "2024-03-30": 78, + "2024-03-29": 79, + "2024-03-28": 79, + "2024-03-27": 79, + "2024-03-26": 78, + "2024-03-25": 78, + "2024-03-24": 78, + "2024-03-23": 78 + }, + "subscription_count": 77, + "utc_period_dates_data": { + "2024-04-22": { + "blog_id": "180619633", + "subscriber_type": "0", + "subscriber_total": "77", + "total": "0", + "hour_00": null, + "hour_01": null, + "hour_02": null, + "hour_03": null, + "hour_04": null, + "hour_05": null, + "hour_06": null, + "hour_07": "-1", + "hour_08": null, + "hour_09": null, + "hour_10": null, + "hour_11": null, + "hour_12": null, + "hour_13": "-1", + "hour_14": null, + "hour_15": "-1", + "hour_16": null, + "hour_17": null, + "hour_18": null, + "hour_19": null, + "hour_20": "-1", + "hour_21": null, + "hour_22": null, + "hour_23": null + }, + "2024-04-21": { + "blog_id": "180619633", + "subscriber_type": "0", + "subscriber_total": "78", + "total": "0", + "hour_00": null, + "hour_01": null, + "hour_02": null, + "hour_03": null, + "hour_04": null, + "hour_05": null, + "hour_06": null, + "hour_07": null, + "hour_08": null, + "hour_09": "-1", + "hour_10": null, + "hour_11": null, + "hour_12": null, + "hour_13": null, + "hour_14": null, + "hour_15": "-2", + "hour_16": null, + "hour_17": null, + "hour_18": "-5", + "hour_19": "-3", + "hour_20": null, + "hour_21": null, + "hour_22": null, + "hour_23": "-2" + }, + "2024-04-20": { + "blog_id": "180619633", + "subscriber_type": "0", + "subscriber_total": "78", + "total": "0", + "hour_00": null, + "hour_01": null, + "hour_02": null, + "hour_03": null, + "hour_04": null, + "hour_05": "-1", + "hour_06": null, + "hour_07": null, + "hour_08": null, + "hour_09": null, + "hour_10": null, + "hour_11": "-1", + "hour_12": null, + "hour_13": null, + "hour_14": null, + "hour_15": "-1", + "hour_16": null, + "hour_17": null, + "hour_18": null, + "hour_19": null, + "hour_20": null, + "hour_21": null, + "hour_22": null, + "hour_23": null + }, + "2024-04-19": { + "blog_id": "180619633", + "subscriber_type": "0", + "subscriber_total": "78", + "total": "0", + "hour_00": null, + "hour_01": null, + "hour_02": null, + "hour_03": null, + "hour_04": null, + "hour_05": null, + "hour_06": "-1", + "hour_07": null, + "hour_08": null, + "hour_09": null, + "hour_10": "-2", + "hour_11": null, + "hour_12": null, + "hour_13": null, + "hour_14": "-1", + "hour_15": null, + "hour_16": "-1", + "hour_17": null, + "hour_18": null, + "hour_19": null, + "hour_20": null, + "hour_21": null, + "hour_22": null, + "hour_23": null + }, + "2024-04-18": { + "blog_id": "180619633", + "subscriber_type": "0", + "subscriber_total": "78", + "total": "0", + "hour_00": null, + "hour_01": null, + "hour_02": null, + "hour_03": null, + "hour_04": null, + "hour_05": null, + "hour_06": "-1", + "hour_07": null, + "hour_08": null, + "hour_09": null, + "hour_10": "-1", + "hour_11": null, + "hour_12": "-1", + "hour_13": null, + "hour_14": null, + "hour_15": null, + "hour_16": "-1", + "hour_17": null, + "hour_18": null, + "hour_19": null, + "hour_20": null, + "hour_21": null, + "hour_22": null, + "hour_23": null + }, + "2024-04-17": { + "blog_id": "180619633", + "subscriber_type": "0", + "subscriber_total": "78", + "total": "0", + "hour_00": null, + "hour_01": null, + "hour_02": null, + "hour_03": null, + "hour_04": null, + "hour_05": null, + "hour_06": null, + "hour_07": "-1", + "hour_08": null, + "hour_09": "-2", + "hour_10": null, + "hour_11": null, + "hour_12": null, + "hour_13": null, + "hour_14": "-2", + "hour_15": "-1", + "hour_16": null, + "hour_17": null, + "hour_18": null, + "hour_19": null, + "hour_20": null, + "hour_21": null, + "hour_22": null, + "hour_23": null + }, + "2024-04-09": { + "blog_id": "180619633", + "subscriber_type": "0", + "subscriber_total": "78", + "total": "2", + "hour_00": null, + "hour_01": null, + "hour_02": null, + "hour_03": null, + "hour_04": null, + "hour_05": null, + "hour_06": null, + "hour_07": null, + "hour_08": null, + "hour_09": null, + "hour_10": null, + "hour_11": null, + "hour_12": null, + "hour_13": null, + "hour_14": null, + "hour_15": "0", + "hour_16": null, + "hour_17": null, + "hour_18": null, + "hour_19": null, + "hour_20": null, + "hour_21": null, + "hour_22": null, + "hour_23": null + }, + "2024-04-04": { + "blog_id": "180619633", + "subscriber_type": "0", + "subscriber_total": "78", + "total": "0", + "hour_00": null, + "hour_01": null, + "hour_02": null, + "hour_03": null, + "hour_04": null, + "hour_05": null, + "hour_06": null, + "hour_07": null, + "hour_08": null, + "hour_09": null, + "hour_10": null, + "hour_11": null, + "hour_12": null, + "hour_13": null, + "hour_14": null, + "hour_15": null, + "hour_16": "-1", + "hour_17": null, + "hour_18": null, + "hour_19": null, + "hour_20": null, + "hour_21": null, + "hour_22": null, + "hour_23": null + }, + "2024-04-01": { + "blog_id": "180619633", + "subscriber_type": "0", + "subscriber_total": "78", + "total": "0", + "hour_00": null, + "hour_01": null, + "hour_02": null, + "hour_03": null, + "hour_04": null, + "hour_05": null, + "hour_06": null, + "hour_07": null, + "hour_08": null, + "hour_09": null, + "hour_10": null, + "hour_11": null, + "hour_12": null, + "hour_13": null, + "hour_14": null, + "hour_15": null, + "hour_16": null, + "hour_17": null, + "hour_18": null, + "hour_19": "-1", + "hour_20": null, + "hour_21": null, + "hour_22": null, + "hour_23": null + }, + "2024-03-31": { + "blog_id": "180619633", + "subscriber_type": "0", + "subscriber_total": "78", + "total": "0", + "hour_00": null, + "hour_01": null, + "hour_02": null, + "hour_03": null, + "hour_04": null, + "hour_05": null, + "hour_06": null, + "hour_07": null, + "hour_08": null, + "hour_09": null, + "hour_10": null, + "hour_11": null, + "hour_12": null, + "hour_13": null, + "hour_14": null, + "hour_15": "-2", + "hour_16": null, + "hour_17": null, + "hour_18": null, + "hour_19": null, + "hour_20": null, + "hour_21": null, + "hour_22": null, + "hour_23": null + }, + "2024-03-29": { + "blog_id": "180619633", + "subscriber_type": "0", + "subscriber_total": "79", + "total": "0", + "hour_00": null, + "hour_01": null, + "hour_02": null, + "hour_03": null, + "hour_04": null, + "hour_05": null, + "hour_06": null, + "hour_07": null, + "hour_08": null, + "hour_09": null, + "hour_10": null, + "hour_11": null, + "hour_12": null, + "hour_13": null, + "hour_14": null, + "hour_15": null, + "hour_16": null, + "hour_17": null, + "hour_18": null, + "hour_19": null, + "hour_20": null, + "hour_21": null, + "hour_22": "-2", + "hour_23": null + }, + "2024-03-26": { + "blog_id": "180619633", + "subscriber_type": "0", + "subscriber_total": "80", + "total": "2", + "hour_00": null, + "hour_01": null, + "hour_02": null, + "hour_03": null, + "hour_04": null, + "hour_05": null, + "hour_06": null, + "hour_07": null, + "hour_08": null, + "hour_09": null, + "hour_10": null, + "hour_11": null, + "hour_12": null, + "hour_13": null, + "hour_14": "2", + "hour_15": null, + "hour_16": null, + "hour_17": null, + "hour_18": null, + "hour_19": null, + "hour_20": null, + "hour_21": null, + "hour_22": null, + "hour_23": null + } + }, + "utc_period_dates_subscriber_total": { + "2024-04-22": 77, + "2024-04-21": 78, + "2024-04-20": 78, + "2024-04-19": 78, + "2024-04-18": 78, + "2024-04-17": 78, + "2024-04-09": 78, + "2024-04-04": 78, + "2024-04-01": 78, + "2024-03-31": 78, + "2024-03-29": 79, + "2024-03-26": 80 + }, + "timezone_all_dates_subscriber_total": { + "2024-04-22": 77, + "2024-04-21": 78, + "2024-04-20": 78, + "2024-04-19": 78, + "2024-04-18": 78, + "2024-04-17": 78, + "2024-04-09": 78, + "2024-04-04": 78, + "2024-04-01": 78, + "2024-03-31": 78, + "2024-03-29": 79, + "2024-03-26": 80 + }, + "timezone": 0, + "gmt_offset": "0", + "detail": { + "blog_id": "123", + "domain": "example.wordpress.com", + "path": "/", + "site_id": "1", + "registered": "2020-07-23 14:06:59", + "last_updated": "2024-04-22 22:57:22", + "public": "-1", + "archived": "0", + "mature": "0", + "spam": "0", + "deleted": "0", + "lang_id": "1", + "ds_blog": "45", + "ds_stats": "0", + "blogname": "Example", + "siteurl": "http://example.wordpress.com", + "post_count": "1877", + "home": "http://example.wordpress.com" + }, + "earliest_date": { + "date": "2024-03-24 00:00:00.000000", + "timezone_type": 1, + "timezone": "+00:00" + }, + "end_date": "2024-04-22 00:00:00" +} diff --git a/Tests/WordPressKitTests/Tests/Models/Stats/V2/StatsSubscribersSummaryDataTests.swift b/Tests/WordPressKitTests/Tests/Models/Stats/V2/StatsSubscribersSummaryDataTests.swift new file mode 100644 index 00000000..71a0ac3e --- /dev/null +++ b/Tests/WordPressKitTests/Tests/Models/Stats/V2/StatsSubscribersSummaryDataTests.swift @@ -0,0 +1,24 @@ +import XCTest +@testable import WordPressKit + +final class StatsSubscribersSummaryDataTests: XCTestCase { + func testEmailsSummaryDecoding() throws { + let json = getJSON("stats-subscribers") + + let summary = StatsSubscribersSummaryData(date: Date(), period: .day, jsonDictionary: json) + XCTAssertNotNil(summary, "StatsSubscribersSummaryData not decoded as expected") + let history = summary!.history + let mostRecentDay = history.last! + + XCTAssertEqual(mostRecentDay.date, StatsSubscribersSummaryData.dateFormatter.date(from: "2024-04-22")) + XCTAssertEqual(mostRecentDay.count, 77) + } +} + +private extension StatsSubscribersSummaryDataTests { + func getJSON(_ fileName: String) -> [String: AnyObject] { + let path = Bundle(for: type(of: self)).path(forResource: fileName, ofType: "json")! + let data = try! Data(contentsOf: URL(fileURLWithPath: path)) + return try! JSONSerialization.jsonObject(with: data, options: .allowFragments) as! [String: AnyObject] + } +} diff --git a/WordPressKit.xcodeproj/project.pbxproj b/WordPressKit.xcodeproj/project.pbxproj index d9e17c81..1b62cab2 100644 --- a/WordPressKit.xcodeproj/project.pbxproj +++ b/WordPressKit.xcodeproj/project.pbxproj @@ -573,6 +573,9 @@ B04D8C0B2BB7895A002717A2 /* stats-insight.json in Resources */ = {isa = PBXBuildFile; fileRef = B04D8C002BB7895A002717A2 /* stats-insight.json */; }; B04D8C0C2BB7895A002717A2 /* stats.json in Resources */ = {isa = PBXBuildFile; fileRef = B04D8C012BB7895A002717A2 /* stats.json */; }; B04D8C0D2BB7895A002717A2 /* StatsInsightDecodingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B04D8C032BB7895A002717A2 /* StatsInsightDecodingTests.swift */; }; + B0E02FBA2BD899F600A0A561 /* StatsSubscribersSummaryDataTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0E02FB62BD8999B00A0A561 /* StatsSubscribersSummaryDataTests.swift */; }; + B0E02FBB2BD89A0400A0A561 /* stats-subscribers.json in Resources */ = {isa = PBXBuildFile; fileRef = B0E02FB82BD899C500A0A561 /* stats-subscribers.json */; }; + B0E02FBD2BD89AAB00A0A561 /* StatsSubscribersSummaryData.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0E02FBC2BD89AAB00A0A561 /* StatsSubscribersSummaryData.swift */; }; B5969E1C20A49AC4005E9DF1 /* NSString+MD5.h in Headers */ = {isa = PBXBuildFile; fileRef = B5969E1920A49AC4005E9DF1 /* NSString+MD5.h */; settings = {ATTRIBUTES = (Public, ); }; }; B5969E1D20A49AC4005E9DF1 /* NSString+MD5.m in Sources */ = {isa = PBXBuildFile; fileRef = B5969E1A20A49AC4005E9DF1 /* NSString+MD5.m */; }; B5A4822B20AC6C0B009D95F6 /* WPKitLogging.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A4822A20AC6C0B009D95F6 /* WPKitLogging.swift */; }; @@ -1329,6 +1332,9 @@ B04D8C002BB7895A002717A2 /* stats-insight.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "stats-insight.json"; sourceTree = ""; }; B04D8C012BB7895A002717A2 /* stats.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = stats.json; sourceTree = ""; }; B04D8C032BB7895A002717A2 /* StatsInsightDecodingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatsInsightDecodingTests.swift; sourceTree = ""; }; + B0E02FB62BD8999B00A0A561 /* StatsSubscribersSummaryDataTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatsSubscribersSummaryDataTests.swift; sourceTree = ""; }; + B0E02FB82BD899C500A0A561 /* stats-subscribers.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "stats-subscribers.json"; sourceTree = ""; }; + B0E02FBC2BD89AAB00A0A561 /* StatsSubscribersSummaryData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatsSubscribersSummaryData.swift; sourceTree = ""; }; B5969E1920A49AC4005E9DF1 /* NSString+MD5.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+MD5.h"; sourceTree = ""; }; B5969E1A20A49AC4005E9DF1 /* NSString+MD5.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+MD5.m"; sourceTree = ""; }; B5A4822A20AC6C0B009D95F6 /* WPKitLogging.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WPKitLogging.swift; sourceTree = ""; }; @@ -1683,6 +1689,7 @@ 3FE2E9362BB10EC7002CA2E1 /* Stats */ = { isa = PBXGroup; children = ( + B0E02FBC2BD89AAB00A0A561 /* StatsSubscribersSummaryData.swift */, 019C5B8A2BD59CE000A69DB0 /* Emails */, 404057C3221B30140060250C /* Time Interval */, 40414061220F9F2800CF7C5B /* Insights */, @@ -2267,6 +2274,7 @@ 93BD27421EE73384002BB00B /* Mock Data */ = { isa = PBXGroup; children = ( + B0E02FB82BD899C500A0A561 /* stats-subscribers.json */, F4B0F4742ACB4176003ABC61 /* Domains */, 937250EB267A15060086075F /* stats-referrer-mark-as-spam.json */, 465F8892263B094900F4C950 /* BlockEditorSettings */, @@ -2628,6 +2636,7 @@ F3FF8A1C279C86F600E5C90F /* V2 */ = { isa = PBXGroup; children = ( + B0E02FB62BD8999B00A0A561 /* StatsSubscribersSummaryDataTests.swift */, 019C5B882BD59C7800A69DB0 /* Emails */, 01383F7D2BD5542300496B76 /* TimeInterval */, F3FF8A1D279C86FE00E5C90F /* Insights */, @@ -2866,6 +2875,7 @@ files = ( 01438D392B6A361B0097D60A /* stats-summary.json in Resources */, 01438D362B6A31540097D60A /* stats-visits-month-unit-week.json in Resources */, + B0E02FBB2BD89A0400A0A561 /* stats-subscribers.json in Resources */, 32A29A1F236BE4CC009488C2 /* post-autosave-mapping-success.json in Resources */, CEAD827B25E421DE00758DF2 /* reader-post-comments-subscribe-failure.json in Resources */, 7403A2FC1EF06FEB00DED7DC /* me-settings-change-lastname-success.json in Resources */, @@ -3384,6 +3394,7 @@ 404057DA221C9D560060250C /* StatsTopReferrersTimeIntervalData.swift in Sources */, 826016F11F9FA13A00533B6C /* ActivityServiceRemote.swift in Sources */, 74BA04FA1F06DC3900ED5CD8 /* RemoteComment.m in Sources */, + B0E02FBD2BD89AAB00A0A561 /* StatsSubscribersSummaryData.swift in Sources */, 40F98809221AC88700B7B369 /* StatsPostingStreakInsight.swift in Sources */, 465F889E263B0C5500F4C950 /* BlockEditorSettingsServiceRemote.swift in Sources */, 32FC1D29255C91ED00CD0A7B /* JetpackScanServiceRemote.swift in Sources */, @@ -3538,6 +3549,7 @@ B04D8C0D2BB7895A002717A2 /* StatsInsightDecodingTests.swift in Sources */, 9F3E0BAE20873836009CB5BA /* ReaderTopicServiceRemoteTest+Subscriptions.swift in Sources */, 4A05E79E2B30F3C500C25E3B /* URLRequest+HTTPBodyText.swift in Sources */, + B0E02FBA2BD899F600A0A561 /* StatsSubscribersSummaryDataTests.swift in Sources */, BA0637ED2492382200AF8419 /* PluginStateTests.swift in Sources */, 7328420621CD798A00126755 /* WordPressComServiceRemoteTests+SiteCreation.swift in Sources */, FACBDD3825ECB4480026705B /* ReaderPostServiceRemote+RelatedPostsTests.swift in Sources */,