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

Commit 6b11bb3

Browse files
authored
Merge pull request #106 from wordpress-mobile/develop
Merge Develop into Master
2 parents 0504a39 + 818ac9d commit 6b11bb3

29 files changed

+8763
-82
lines changed

Podfile

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,12 @@ plugin 'cocoapods-repo-update'
1010
## =============
1111
##
1212
target 'WordPressKit' do
13-
pod "WordPressKit", :path => "./"
13+
pod 'Alamofire', '~> 4.7.3'
14+
pod 'CocoaLumberjack', '3.4.2'
15+
pod 'WordPressShared', '~> 1.4'
16+
pod 'NSObject-SafeExpectations', '~> 0.0.3'
17+
pod 'wpxmlrpc', '0.8.4'
18+
pod 'UIDeviceIdentifier', '~> 1.1.4'
1419

1520
target 'WordPressKitTests' do
1621
inherit! :search_paths

Podfile.lock

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -27,24 +27,21 @@ PODS:
2727
- OHHTTPStubs/Swift (6.1.0):
2828
- OHHTTPStubs/Default
2929
- UIDeviceIdentifier (1.1.4)
30-
- WordPressKit (2.1.0-beta.2):
31-
- Alamofire (~> 4.7.3)
32-
- CocoaLumberjack (= 3.4.2)
33-
- NSObject-SafeExpectations (= 0.0.3)
34-
- UIDeviceIdentifier (~> 1.1.4)
35-
- WordPressShared (~> 1.4)
36-
- wpxmlrpc (= 0.8.4)
3730
- WordPressShared (1.7.0):
3831
- CocoaLumberjack (~> 3.4)
3932
- FormatterKit/TimeIntervalFormatter (= 1.8.2)
4033
- wpxmlrpc (0.8.4)
4134

4235
DEPENDENCIES:
36+
- Alamofire (~> 4.7.3)
37+
- CocoaLumberjack (= 3.4.2)
38+
- NSObject-SafeExpectations (~> 0.0.3)
4339
- OCMock (~> 3.4.2)
4440
- OHHTTPStubs (= 6.1.0)
4541
- OHHTTPStubs/Swift (= 6.1.0)
46-
- WordPressKit (from `./`)
42+
- UIDeviceIdentifier (~> 1.1.4)
4743
- WordPressShared (~> 1.4)
44+
- wpxmlrpc (= 0.8.4)
4845

4946
SPEC REPOS:
5047
https://github.com/cocoapods/specs.git:
@@ -58,10 +55,6 @@ SPEC REPOS:
5855
- WordPressShared
5956
- wpxmlrpc
6057

61-
EXTERNAL SOURCES:
62-
WordPressKit:
63-
:path: "./"
64-
6558
SPEC CHECKSUMS:
6659
Alamofire: c7287b6e5d7da964a70935e5db17046b7fde6568
6760
CocoaLumberjack: db7cc9e464771f12054c22ff6947c5a58d43a0fd
@@ -70,10 +63,9 @@ SPEC CHECKSUMS:
7063
OCMock: 43565190abc78977ad44a61c0d20d7f0784d35ab
7164
OHHTTPStubs: 1e21c7d2c084b8153fc53d48400d8919d2d432d0
7265
UIDeviceIdentifier: 8f8a24b257a4d978c8d40ad1e7355b944ffbfa8c
73-
WordPressKit: 36e5966f63f88efc51c6a3de4aa07dbd66eb15cc
7466
WordPressShared: cfbda56868419842dd7a106a4e807069a0c17aa9
7567
wpxmlrpc: 6ba55c773cfa27083ae4a2173e69b19f46da98e2
7668

77-
PODFILE CHECKSUM: 96aee46d567751451860e27dd476d15d79b40f44
69+
PODFILE CHECKSUM: 34d4f957f37c097c360d2863370ce2e5e06511cc
7870

7971
COCOAPODS: 1.5.3

WordPressKit.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Pod::Spec.new do |s|
22
s.name = "WordPressKit"
3-
s.version = "2.1.0-beta.2"
3+
s.version = "2.1.0"
44
s.summary = "WordPressKit offers a clean and simple WordPress.com and WordPress.org API."
55

66
s.description = <<-DESC

WordPressKit.xcodeproj/project.pbxproj

Lines changed: 100 additions & 2 deletions
Large diffs are not rendered by default.
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
public struct StatsLastPostInsight {
2+
public let title: String
3+
public let url: URL
4+
public let publishedDate: Date
5+
public let likesCount: Int
6+
public let commentsCount: Int
7+
public let viewsCount: Int
8+
public let postID: Int
9+
}
10+
11+
extension StatsLastPostInsight: InsightProtocol {
12+
13+
//MARK: - InsightProtocol Conformance
14+
public static var queryProperties: [String: String] {
15+
return ["order_by": "date",
16+
"number": "1",
17+
"type": "post",
18+
"fields": "ID, title, URL, discussion, like_count, date"]
19+
}
20+
21+
public static var pathComponent: String {
22+
return "posts/"
23+
}
24+
25+
public init?(jsonDictionary: [String: AnyObject]) {
26+
fatalError("This shouldn't be ever called, instead init?(jsonDictionary:_ views:_) be called instead.")
27+
}
28+
29+
//MARK: -
30+
31+
private static let dateFormatter = ISO8601DateFormatter()
32+
33+
public init?(jsonDictionary: [String: AnyObject], views: Int) {
34+
35+
guard
36+
let title = jsonDictionary["title"] as? String,
37+
let dateString = jsonDictionary["date"] as? String,
38+
let urlString = jsonDictionary["URL"] as? String,
39+
let likesCount = jsonDictionary["like_count"] as? Int,
40+
let postID = jsonDictionary["ID"] as? Int,
41+
let discussionDict = jsonDictionary["discussion"] as? [String: Any],
42+
let commentsCount = discussionDict["comment_count"] as? Int
43+
else {
44+
return nil
45+
}
46+
47+
guard
48+
let url = URL(string: urlString),
49+
let date = StatsLastPostInsight.dateFormatter.date(from: dateString)
50+
else {
51+
return nil
52+
}
53+
54+
self.title = title.trimmingCharacters(in: CharacterSet.whitespaces).stringByDecodingXMLCharacters()
55+
self.url = url
56+
self.publishedDate = date
57+
self.likesCount = likesCount
58+
self.commentsCount = commentsCount
59+
self.viewsCount = views
60+
self.postID = postID
61+
}
62+
}
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
public struct StatsPostDetails {
2+
public let fetchedDate: Date
3+
public let totalViewsCount: Int
4+
5+
public let recentWeeks: [StatsWeeklyBreakdown]
6+
public let dailyAveragesPerMonth: [StatsPostViews]
7+
public let monthlyBreakdown: [StatsPostViews]
8+
public let lastTwoWeeks: [StatsPostViews]
9+
}
10+
11+
public struct StatsWeeklyBreakdown {
12+
public let startDay: DateComponents
13+
public let endDay: DateComponents
14+
15+
public let totalViewsCount: Int
16+
public let averageViewsCount: Int
17+
public let changePercentage: Double
18+
19+
public let days: [StatsPostViews]
20+
}
21+
22+
public struct StatsPostViews {
23+
public let period: StatsPeriodUnit
24+
public let date: DateComponents
25+
public let viewsCount: Int
26+
}
27+
28+
extension StatsPostDetails {
29+
init?(jsonDictionary: [String: AnyObject]) {
30+
guard
31+
let fetchedDateString = jsonDictionary["date"] as? String,
32+
let date = type(of: self).dateFormatter.date(from: fetchedDateString),
33+
let totalViewsCount = jsonDictionary["views"] as? Int,
34+
let monthlyBreakdown = jsonDictionary["years"] as? [String: AnyObject],
35+
let monthlyAverages = jsonDictionary["averages"] as? [String: AnyObject],
36+
let recentWeeks = jsonDictionary["weeks"] as? [[String: AnyObject]],
37+
let data = jsonDictionary["data"] as? [[Any]]
38+
else {
39+
return nil
40+
}
41+
42+
self.fetchedDate = date
43+
self.totalViewsCount = totalViewsCount
44+
45+
// It's very hard to describe the format of this response. I tried to make the parsing
46+
// as nice and readable as possible, but in all honestly it's still pretty nasty.
47+
// If you want to see an example response to see how weird this response is, check out
48+
// `stats-post-details.json`.
49+
self.recentWeeks = StatsPostViews.mapWeeklyBreakdown(jsonDictionary: recentWeeks)
50+
self.monthlyBreakdown = StatsPostViews.mapMonthlyBreakdown(jsonDictionary: monthlyBreakdown)
51+
self.dailyAveragesPerMonth = StatsPostViews.mapMonthlyBreakdown(jsonDictionary: monthlyAverages)
52+
self.lastTwoWeeks = StatsPostViews.mapDailyData(data: Array(data.suffix(14)))
53+
}
54+
55+
static var dateFormatter: DateFormatter {
56+
let df = DateFormatter()
57+
df.locale = Locale(identifier: "en_US_POS")
58+
df.dateFormat = "yyyy-MM-dd"
59+
return df
60+
}
61+
}
62+
63+
extension StatsPostViews {
64+
static func mapMonthlyBreakdown(jsonDictionary: [String: AnyObject]) -> [StatsPostViews] {
65+
return jsonDictionary.flatMap { yearKey, value -> [StatsPostViews] in
66+
guard
67+
let yearInt = Int(yearKey),
68+
let monthsDict = value as? [String: AnyObject],
69+
let months = monthsDict["months"] as? [String: Int]
70+
else {
71+
return []
72+
}
73+
74+
return months.compactMap { monthKey, value in
75+
guard
76+
let month = Int(monthKey)
77+
else {
78+
return nil
79+
}
80+
81+
return StatsPostViews(period: .month,
82+
date: DateComponents(year: yearInt, month: month),
83+
viewsCount: value)
84+
}
85+
}
86+
}
87+
}
88+
89+
extension StatsPostViews {
90+
static func mapWeeklyBreakdown(jsonDictionary: [[String: AnyObject]]) -> [StatsWeeklyBreakdown] {
91+
return jsonDictionary.compactMap {
92+
guard
93+
let totalViews = $0["total"] as? Int,
94+
let averageViews = $0["average"] as? Int,
95+
let days = $0["days"] as? [[String: AnyObject]]
96+
else {
97+
return nil
98+
}
99+
100+
let change = ($0["change"] as? Double) ?? 0.0
101+
102+
let mappedDays: [StatsPostViews] = days.compactMap {
103+
guard
104+
let dayString = $0["day"] as? String,
105+
let date = StatsPostDetails.dateFormatter.date(from: dayString),
106+
let viewsCount = $0["count"] as? Int
107+
else {
108+
return nil
109+
}
110+
111+
return StatsPostViews(period: .day,
112+
date: Calendar.autoupdatingCurrent.dateComponents([.year, .month, .day], from: date),
113+
viewsCount: viewsCount)
114+
}
115+
116+
guard !mappedDays.isEmpty else {
117+
return nil
118+
}
119+
120+
121+
return StatsWeeklyBreakdown(startDay: mappedDays.first!.date,
122+
endDay: mappedDays.last!.date,
123+
totalViewsCount: totalViews,
124+
averageViewsCount: averageViews,
125+
changePercentage: change,
126+
days: mappedDays)
127+
}
128+
129+
}
130+
}
131+
132+
extension StatsPostViews {
133+
static func mapDailyData(data: [[Any]]) -> [StatsPostViews] {
134+
return data.compactMap {
135+
guard
136+
let dateString = $0[0] as? String,
137+
let date = StatsPostDetails.dateFormatter.date(from: dateString),
138+
let viewsCount = $0[1] as? Int
139+
else {
140+
return nil
141+
}
142+
143+
return StatsPostViews(period: .day,
144+
date: Calendar.autoupdatingCurrent.dateComponents([.year, .month, .day], from: date),
145+
viewsCount: viewsCount)
146+
}
147+
}
148+
}

0 commit comments

Comments
 (0)