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

Commit 0504a39

Browse files
authored
Merge pull request #92 from wordpress-mobile/feature/insights-streak-fetching
Stats: fetching Streak insight
2 parents 1b1c9f9 + 850f876 commit 0504a39

File tree

4 files changed

+189
-0
lines changed

4 files changed

+189
-0
lines changed

WordPressKit.xcodeproj/project.pbxproj

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@
3232
40E7FEBA2210894B0032834E /* StatsTagsAndCategoriesInsight.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40E7FEB92210894B0032834E /* StatsTagsAndCategoriesInsight.swift */; };
3333
40F88F601F85723500AE3FAF /* auth-send-verification-email-already-verified-failure.json in Resources */ = {isa = PBXBuildFile; fileRef = 40F88F5F1F85723400AE3FAF /* auth-send-verification-email-already-verified-failure.json */; };
3434
40F88F621F85799A00AE3FAF /* auth-send-verification-email-success.json in Resources */ = {isa = PBXBuildFile; fileRef = 40F88F611F85799A00AE3FAF /* auth-send-verification-email-success.json */; };
35+
40F98809221AC88700B7B369 /* StatsPostingStreakInsight.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40F98808221AC88700B7B369 /* StatsPostingStreakInsight.swift */; };
36+
40F9880C221ACEEE00B7B369 /* StatsRemoteV2Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40F9880B221ACEEE00B7B369 /* StatsRemoteV2Tests.swift */; };
37+
40F9880E221ACFB400B7B369 /* stats-streak-result.json in Resources */ = {isa = PBXBuildFile; fileRef = 40F9880D221ACFB400B7B369 /* stats-streak-result.json */; };
3538
436D56332118D7AA00CEAA33 /* TransactionsServiceRemote.swift in Sources */ = {isa = PBXBuildFile; fileRef = 436D56322118D7AA00CEAA33 /* TransactionsServiceRemote.swift */; };
3639
436D56352118D85800CEAA33 /* Country.swift in Sources */ = {isa = PBXBuildFile; fileRef = 436D56342118D85800CEAA33 /* Country.swift */; };
3740
436D56382118DC4B00CEAA33 /* TransactionsServiceRemoteTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 436D56372118DC4B00CEAA33 /* TransactionsServiceRemoteTests.swift */; };
@@ -501,6 +504,9 @@
501504
40E7FEB92210894B0032834E /* StatsTagsAndCategoriesInsight.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatsTagsAndCategoriesInsight.swift; sourceTree = "<group>"; };
502505
40F88F5F1F85723400AE3FAF /* auth-send-verification-email-already-verified-failure.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "auth-send-verification-email-already-verified-failure.json"; sourceTree = "<group>"; };
503506
40F88F611F85799A00AE3FAF /* auth-send-verification-email-success.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "auth-send-verification-email-success.json"; sourceTree = "<group>"; };
507+
40F98808221AC88700B7B369 /* StatsPostingStreakInsight.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatsPostingStreakInsight.swift; sourceTree = "<group>"; };
508+
40F9880B221ACEEE00B7B369 /* StatsRemoteV2Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatsRemoteV2Tests.swift; sourceTree = "<group>"; };
509+
40F9880D221ACFB400B7B369 /* stats-streak-result.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "stats-streak-result.json"; sourceTree = "<group>"; };
504510
436D56322118D7AA00CEAA33 /* TransactionsServiceRemote.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransactionsServiceRemote.swift; sourceTree = "<group>"; };
505511
436D56342118D85800CEAA33 /* Country.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Country.swift; sourceTree = "<group>"; };
506512
436D56372118DC4B00CEAA33 /* TransactionsServiceRemoteTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransactionsServiceRemoteTests.swift; sourceTree = "<group>"; };
@@ -992,6 +998,7 @@
992998
40E7FEB3221063480032834E /* StatsTodayInsight.swift */,
993999
40E7FEB622106A8D0032834E /* StatsCommentsInsight.swift */,
9941000
40E7FEB92210894B0032834E /* StatsTagsAndCategoriesInsight.swift */,
1001+
40F98808221AC88700B7B369 /* StatsPostingStreakInsight.swift */,
9951002
);
9961003
path = Insights;
9971004
sourceTree = "<group>";
@@ -1206,6 +1213,7 @@
12061213
930F52BB1ECF8A78002F921B /* Stats */ = {
12071214
isa = PBXGroup;
12081215
children = (
1216+
40F9880B221ACEEE00B7B369 /* StatsRemoteV2Tests.swift */,
12091217
93AC8EE31ED32FDA00900F5A /* Test Data */,
12101218
93AC8EBF1ED32FD000900F5A /* StatsItemTests.m */,
12111219
93AC8EC01ED32FD000900F5A /* StatsStreakItemTests.m */,
@@ -1491,6 +1499,7 @@
14911499
93BD27421EE73384002BB00B /* Mock Data */ = {
14921500
isa = PBXGroup;
14931501
children = (
1502+
40F9880D221ACFB400B7B369 /* stats-streak-result.json */,
14941503
826016F61F9FAF6300533B6C /* activity-log-auth-failure.json */,
14951504
826016F81F9FAF6300533B6C /* activity-log-bad-json-failure.json */,
14961505
826016F51F9FAF6300533B6C /* activity-log-success-1.json */,
@@ -2089,6 +2098,7 @@
20892098
826016FB1F9FAF6300533B6C /* activity-log-auth-failure.json in Resources */,
20902099
73D592FB21E550D300E4CF84 /* site-verticals-multiple.json in Resources */,
20912100
7403A2F61EF06FEB00DED7DC /* me-settings-change-aboutme-success.json in Resources */,
2101+
40F9880E221ACFB400B7B369 /* stats-streak-result.json in Resources */,
20922102
7403A2FA1EF06FEB00DED7DC /* me-settings-change-firstname-success.json in Resources */,
20932103
74D67F321F15C3740010C5ED /* site-followers-delete-success.json in Resources */,
20942104
93F50A481F227F3600B5BEBA /* xmlrpc-response-valid-but-unexpected-dictionary.xml in Resources */,
@@ -2256,6 +2266,7 @@
22562266
826016F11F9FA13A00533B6C /* ActivityServiceRemote.swift in Sources */,
22572267
74BA04FA1F06DC3900ED5CD8 /* RemoteComment.m in Sources */,
22582268
7E3E7A4C20E443AA0075D159 /* NSMutableParagraphStyle+extensions.swift in Sources */,
2269+
40F98809221AC88700B7B369 /* StatsPostingStreakInsight.swift in Sources */,
22592270
93C674EC1EE8348F00BFAF05 /* RemoteBlogOptionsHelper.m in Sources */,
22602271
E632D7781F6E047400297F6D /* SocialLogin2FANonceInfo.swift in Sources */,
22612272
9F3E0B9B208732B3009CB5BA /* RemoteReaderSiteInfoSubscription.swift in Sources */,
@@ -2355,6 +2366,7 @@
23552366
74585B901F0D51F900E7E667 /* DomainsServiceRemoteRESTTests.swift in Sources */,
23562367
9AB6D64A218727D60008F274 /* PostServiceRemoteRESTRevisionsTest.swift in Sources */,
23572368
7430C9BD1F192C0F0051B8E6 /* ReaderPostServiceRemoteTests.m in Sources */,
2369+
40F9880C221ACEEE00B7B369 /* StatsRemoteV2Tests.swift in Sources */,
23582370
826017001F9FD60A00533B6C /* ActivityServiceRemoteTests.swift in Sources */,
23592371
93F50A3A1F226BB600B5BEBA /* WordPressComServiceRemoteRestTests.swift in Sources */,
23602372
93AC8EE01ED32FD000900F5A /* StatsStreakTests.m in Sources */,
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
public struct StatsPostingStreakInsight {
2+
public let currentStreakStart: Date
3+
public let currentStreakEnd: Date
4+
public let currentStreakLength: Int
5+
public let longestStreakStart: Date
6+
public let longestStreakEnd: Date
7+
public let longestStreakLength: Int
8+
9+
public let postingEvents: [PostingStreakEvent]
10+
}
11+
12+
public struct PostingStreakEvent {
13+
public let date: Date
14+
public let postCount: Int
15+
}
16+
17+
extension StatsPostingStreakInsight: InsightProtocol {
18+
19+
//MARK: - InsightProtocol Conformance
20+
public static var pathComponent: String {
21+
return "stats/streak"
22+
}
23+
24+
public init?(jsonDictionary: [String: AnyObject]) {
25+
guard
26+
let postsData = jsonDictionary["data"] as? [String: AnyObject],
27+
let streaks = jsonDictionary["streak"] as? [String: AnyObject],
28+
let longestData = streaks["long"] as? [String: AnyObject],
29+
let currentData = streaks["current"] as? [String: AnyObject],
30+
let longestStart = longestData["start"] as? String,
31+
let longestStartDate = StatsPostingStreakInsight.dateFormatter.date(from: longestStart),
32+
let longestEnd = longestData["end"] as? String,
33+
let longestEndDate = StatsPostingStreakInsight.dateFormatter.date(from: longestEnd),
34+
let longestLength = longestData["length"] as? Int,
35+
let currentStart = currentData["start"] as? String,
36+
let currentStartDate = StatsPostingStreakInsight.dateFormatter.date(from: currentStart),
37+
let currentEnd = currentData["end"] as? String,
38+
let currentEndDate = StatsPostingStreakInsight.dateFormatter.date(from: currentEnd),
39+
let currentLength = currentData["length"] as? Int
40+
else {
41+
return nil
42+
}
43+
44+
let postingDates = postsData.keys
45+
.compactMap { Double($0) }
46+
.map { Date(timeIntervalSince1970: $0) }
47+
.map { Calendar.autoupdatingCurrent.startOfDay(for: $0) }
48+
49+
let countedPosts = NSCountedSet(array: postingDates)
50+
51+
let postingEvents = countedPosts.map {
52+
PostingStreakEvent(date: $0 as! Date, postCount: countedPosts.count(for: $0))
53+
}
54+
55+
self.currentStreakStart = currentStartDate
56+
self.currentStreakEnd = currentEndDate
57+
self.currentStreakLength = currentLength
58+
self.longestStreakStart = longestStartDate
59+
self.longestStreakEnd = longestEndDate
60+
self.longestStreakLength = longestLength
61+
self.postingEvents = postingEvents
62+
}
63+
64+
private static var dateFormatter: DateFormatter {
65+
let formatter = DateFormatter()
66+
formatter.dateFormat = "yyyy-MM-dd"
67+
return formatter
68+
}
69+
70+
71+
72+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
{
2+
"streak": {
3+
"long": {
4+
"start": "2018-03-28",
5+
"end": "2018-03-29",
6+
"length": 2
7+
},
8+
"current": {
9+
"start": "2019-02-07",
10+
"end": "2019-02-07",
11+
"length": 1
12+
}
13+
},
14+
"data": {
15+
"1517591300": 1,
16+
"1518633236": 1,
17+
"1521558018": 1,
18+
"1522252824": 1,
19+
"1522339253": 1,
20+
"1524502854": 1,
21+
"1525386728": 1,
22+
"1525879841": 1,
23+
"1526299248": 1,
24+
"1526325694": 1,
25+
"1529366487": 1,
26+
"1529589654": 1,
27+
"1529598045": 1,
28+
"1532369350": 1,
29+
"1532617690": 1,
30+
"1533214805": 1,
31+
"1534248027": 1,
32+
"1535736246": 1,
33+
"1536768805": 1,
34+
"1537873250": 1,
35+
"1538150452": 1,
36+
"1540912843": 1,
37+
"1541516765": 1,
38+
"1542216078": 1,
39+
"1542742308": 1,
40+
"1543265213": 1,
41+
"1543420856": 1,
42+
"1543863772": 1,
43+
"1545235219": 1,
44+
"1546513243": 1,
45+
"1546971252": 1,
46+
"1547431243": 1,
47+
"1549555242": 1
48+
}
49+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import Foundation
2+
import XCTest
3+
@testable import WordPressKit
4+
5+
class StatsRemoteV2Tests: RemoteTestCase, RESTTestable {
6+
7+
// MARK: - Constants
8+
9+
let siteID = 321
10+
11+
let getStreakMockFilename = "stats-streak-result.json"
12+
13+
// MARK: - Properties
14+
15+
var siteStreakEndpoint: String { return "sites/\(siteID)/stats/streak" }
16+
var remote: StatsServiceRemoteV2!
17+
18+
// MARK: - Overridden Methods
19+
20+
override func setUp() {
21+
super.setUp()
22+
remote = StatsServiceRemoteV2(wordPressComRestApi: getRestApi(), siteID: siteID, siteTimezone: .autoupdatingCurrent)
23+
}
24+
25+
func testFetchStreaks() {
26+
let expect = expectation(description: "It should return streak data")
27+
28+
stubRemoteResponse(siteStreakEndpoint, filename: getStreakMockFilename, contentType: .ApplicationJSON)
29+
30+
remote.getInsight { (insight: StatsPostingStreakInsight?, error: Error?) in
31+
XCTAssertNil(error)
32+
XCTAssertNotNil(insight)
33+
XCTAssertEqual(insight?.postingEvents.count, 31)
34+
XCTAssertEqual(insight?.postingEvents.filter { $0.postCount == 1}.count, 29)
35+
XCTAssertEqual(insight?.postingEvents.filter { $0.postCount == 2}.count, 2)
36+
37+
let calendar = Calendar.autoupdatingCurrent
38+
39+
let march28 = DateComponents(year: 2018, month: 3, day: 28)
40+
let march29 = DateComponents(year: 2018, month: 3, day: 29)
41+
let feb7 = DateComponents(year: 2019, month: 2, day: 7)
42+
43+
XCTAssertEqual(insight?.longestStreakStart, calendar.date(from: march28))
44+
XCTAssertEqual(insight?.longestStreakEnd, calendar.date(from: march29))
45+
XCTAssertEqual(insight?.longestStreakLength, 2)
46+
47+
XCTAssertEqual(insight?.currentStreakStart, calendar.date(from: feb7))
48+
XCTAssertEqual(insight?.currentStreakEnd, calendar.date(from: feb7))
49+
XCTAssertEqual(insight?.currentStreakLength, 1)
50+
51+
expect.fulfill()
52+
}
53+
54+
waitForExpectations(timeout: timeout, handler: nil)
55+
}
56+
}

0 commit comments

Comments
 (0)