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

Commit 5ce3d14

Browse files
authored
Merge pull request #626 from wordpress-mobile/task/add-all-domains-endpoint
2 parents 9e3af4c + 423a5f0 commit 5ce3d14

File tree

8 files changed

+675
-16
lines changed

8 files changed

+675
-16
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ _None._
3838

3939
### New Features
4040

41-
_None._
41+
- Add an API in `DomainServiceRemote` to fetch All Domains. [#626]
4242

4343
### Bug Fixes
4444

WordPressKit.xcodeproj/project.pbxproj

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,9 @@
606606
F3FF8A25279C960F00E5C90F /* site-email-followers-get-auth-failure.json in Resources */ = {isa = PBXBuildFile; fileRef = F3FF8A24279C960F00E5C90F /* site-email-followers-get-auth-failure.json */; };
607607
F3FF8A27279C967200E5C90F /* site-email-followers-get-failure.json in Resources */ = {isa = PBXBuildFile; fileRef = F3FF8A26279C967200E5C90F /* site-email-followers-get-failure.json */; };
608608
F3FF8A29279C991B00E5C90F /* site-email-followers-get-success-more-pages.json in Resources */ = {isa = PBXBuildFile; fileRef = F3FF8A28279C991B00E5C90F /* site-email-followers-get-success-more-pages.json */; };
609+
F4B0F4732ACAF498003ABC61 /* DomainsServiceRemote+AllDomains.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4B0F4722ACAF498003ABC61 /* DomainsServiceRemote+AllDomains.swift */; };
610+
F4B0F47C2ACB4B74003ABC61 /* get-all-domains-response.json in Resources */ = {isa = PBXBuildFile; fileRef = F4B0F47B2ACB4B74003ABC61 /* get-all-domains-response.json */; };
611+
F4B0F4802ACB4EA9003ABC61 /* AllDomainsResultDomainTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4B0F47F2ACB4EA9003ABC61 /* AllDomainsResultDomainTests.swift */; };
609612
F9E56DF624EB11EF00916770 /* FeatureFlag.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9E56DF524EB11EF00916770 /* FeatureFlag.swift */; };
610613
F9E56DF824EB125600916770 /* FeatureFlagRemote.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9E56DF724EB125600916770 /* FeatureFlagRemote.swift */; };
611614
F9E56DFB24EB18C300916770 /* FeatureFlagRemoteTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9E56DFA24EB18C300916770 /* FeatureFlagRemoteTests.swift */; };
@@ -1305,6 +1308,9 @@
13051308
F3FF8A24279C960F00E5C90F /* site-email-followers-get-auth-failure.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "site-email-followers-get-auth-failure.json"; sourceTree = "<group>"; };
13061309
F3FF8A26279C967200E5C90F /* site-email-followers-get-failure.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "site-email-followers-get-failure.json"; sourceTree = "<group>"; };
13071310
F3FF8A28279C991B00E5C90F /* site-email-followers-get-success-more-pages.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "site-email-followers-get-success-more-pages.json"; sourceTree = "<group>"; };
1311+
F4B0F4722ACAF498003ABC61 /* DomainsServiceRemote+AllDomains.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DomainsServiceRemote+AllDomains.swift"; sourceTree = "<group>"; };
1312+
F4B0F47B2ACB4B74003ABC61 /* get-all-domains-response.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "get-all-domains-response.json"; sourceTree = "<group>"; };
1313+
F4B0F47F2ACB4EA9003ABC61 /* AllDomainsResultDomainTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllDomainsResultDomainTests.swift; sourceTree = "<group>"; };
13081314
F9E56DF524EB11EF00916770 /* FeatureFlag.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeatureFlag.swift; sourceTree = "<group>"; };
13091315
F9E56DF724EB125600916770 /* FeatureFlagRemote.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeatureFlagRemote.swift; sourceTree = "<group>"; };
13101316
F9E56DFA24EB18C300916770 /* FeatureFlagRemoteTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeatureFlagRemoteTests.swift; sourceTree = "<group>"; };
@@ -1610,6 +1616,7 @@
16101616
isa = PBXGroup;
16111617
children = (
16121618
74585B8F1F0D51F900E7E667 /* DomainsServiceRemoteRESTTests.swift */,
1619+
F4B0F47F2ACB4EA9003ABC61 /* AllDomainsResultDomainTests.swift */,
16131620
);
16141621
name = Domains;
16151622
sourceTree = "<group>";
@@ -1878,6 +1885,7 @@
18781885
9368C79B1EC62EB70092CE8E /* Services */ = {
18791886
isa = PBXGroup;
18801887
children = (
1888+
F4B0F4712ACAF47D003ABC61 /* Domains */,
18811889
93BD27381EE73282002BB00B /* AccountServiceRemote.h */,
18821890
93BD27391EE73282002BB00B /* AccountServiceRemoteREST.h */,
18831891
93BD273A1EE73282002BB00B /* AccountServiceRemoteREST.m */,
@@ -1904,7 +1912,6 @@
19041912
74BA04F01F06DC0A00ED5CD8 /* CommentServiceRemoteXMLRPC.h */,
19051913
74BA04F11F06DC0A00ED5CD8 /* CommentServiceRemoteXMLRPC.m */,
19061914
8BB5F62027A99A2000B2FFAF /* DashboardServiceRemote.swift */,
1907-
74585B8D1F0D51A100E7E667 /* DomainsServiceRemote.swift */,
19081915
7E0D64FE22D855700092AD10 /* EditorServiceRemote.swift */,
19091916
E182BF691FD961810001D850 /* Endpoint.swift */,
19101917
F9E56DF724EB125600916770 /* FeatureFlagRemote.swift */,
@@ -2099,6 +2106,7 @@
20992106
93BD27421EE73384002BB00B /* Mock Data */ = {
21002107
isa = PBXGroup;
21012108
children = (
2109+
F4B0F4742ACB4176003ABC61 /* Domains */,
21022110
937250EB267A15060086075F /* stats-referrer-mark-as-spam.json */,
21032111
465F8892263B094900F4C950 /* BlockEditorSettings */,
21042112
FA4261712570CC91003A01E2 /* activity-groups-bad-json-failure.json */,
@@ -2588,6 +2596,23 @@
25882596
path = Insights;
25892597
sourceTree = "<group>";
25902598
};
2599+
F4B0F4712ACAF47D003ABC61 /* Domains */ = {
2600+
isa = PBXGroup;
2601+
children = (
2602+
74585B8D1F0D51A100E7E667 /* DomainsServiceRemote.swift */,
2603+
F4B0F4722ACAF498003ABC61 /* DomainsServiceRemote+AllDomains.swift */,
2604+
);
2605+
path = Domains;
2606+
sourceTree = "<group>";
2607+
};
2608+
F4B0F4742ACB4176003ABC61 /* Domains */ = {
2609+
isa = PBXGroup;
2610+
children = (
2611+
F4B0F47B2ACB4B74003ABC61 /* get-all-domains-response.json */,
2612+
);
2613+
path = Domains;
2614+
sourceTree = "<group>";
2615+
};
25912616
F9E56DF924EB18A300916770 /* Utilities */ = {
25922617
isa = PBXGroup;
25932618
children = (
@@ -3015,6 +3040,7 @@
30153040
C738CAF928622BB1001BE107 /* qrlogin-authenticate-failed-400.json in Resources */,
30163041
74D67F1E1F15C3240010C5ED /* people-send-invitation-failure.json in Resources */,
30173042
7403A3001EF06FEB00DED7DC /* me-settings-success.json in Resources */,
3043+
F4B0F47C2ACB4B74003ABC61 /* get-all-domains-response.json in Resources */,
30183044
FEE48EF82A4B3E43008A48E0 /* sites-site-active-features.json in Resources */,
30193045
439A44DE2107CF6F00795ED7 /* site-plans-v3-bad-json-failure.json in Resources */,
30203046
74B335EA1F06F76B0053A184 /* xmlrpc-response-getpost.xml in Resources */,
@@ -3246,6 +3272,7 @@
32463272
E194CB731FBDEF6500B0A8B8 /* PluginState.swift in Sources */,
32473273
404057D6221C92660060250C /* StatsTopClicksTimeIntervalData.swift in Sources */,
32483274
9AF4F2FC218331DC00570E4B /* PostServiceRemoteREST+Revisions.swift in Sources */,
3275+
F4B0F4732ACAF498003ABC61 /* DomainsServiceRemote+AllDomains.swift in Sources */,
32493276
E13EE1471F33258E00C15787 /* PluginServiceRemote.swift in Sources */,
32503277
93BD276A1EE736A8002BB00B /* RemoteUser.m in Sources */,
32513278
742362D71F10250600BD0A7F /* MenusServiceRemote.m in Sources */,
@@ -3406,6 +3433,7 @@
34063433
BA0637ED2492382200AF8419 /* PluginStateTests.swift in Sources */,
34073434
7328420621CD798A00126755 /* WordPressComServiceRemoteTests+SiteCreation.swift in Sources */,
34083435
FACBDD3825ECB4480026705B /* ReaderPostServiceRemote+RelatedPostsTests.swift in Sources */,
3436+
F4B0F4802ACB4EA9003ABC61 /* AllDomainsResultDomainTests.swift in Sources */,
34093437
74585B901F0D51F900E7E667 /* DomainsServiceRemoteRESTTests.swift in Sources */,
34103438
BAFA775624ADAB3C000F0D3A /* MockPluginDirectoryEntryProvider.swift in Sources */,
34113439
3F8308A729EE683500354497 /* ActivityTests.swift in Sources */,
Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
import Foundation
2+
3+
extension DomainsServiceRemote {
4+
5+
// MARK: - API
6+
7+
/// Makes a call request to `GET /v1.1/all-domains` and returns a list of domain objects.
8+
///
9+
/// The endpoint accepts 3 **optionals** query params:
10+
/// - `resolve_status` of type `boolean`. If `true`, the response will include a `status` attribute for each `domain` object.
11+
/// - `no_wpcom`of type `boolean`. If `true`, the respnse won't include `wpcom` domains.
12+
/// - `locale` of type `string`. Used for string localization.
13+
public func fetchAllDomains(params: AllDomainsEndpointParams? = nil, completion: @escaping (AllDomainsEndpointResult) -> Void) {
14+
let path = self.path(forEndpoint: "all-domains", withVersion: ._1_1)
15+
var parameters: [String: AnyObject]?
16+
17+
do {
18+
parameters = try queryParameters(from: params)
19+
} catch let error {
20+
completion(.failure(error))
21+
return
22+
}
23+
24+
self.wordPressComRestApi.GET(path, parameters: parameters) { result, _ in
25+
do {
26+
switch result {
27+
case .success(let result):
28+
let data = try JSONSerialization.data(withJSONObject: result, options: [])
29+
let decoder = JSONDecoder()
30+
decoder.dateDecodingStrategy = .iso8601
31+
let result = try decoder.decode(AllDomainsEndpointResponse.self, from: data)
32+
completion(.success(result.domains))
33+
case .failure(let error):
34+
throw error
35+
}
36+
} catch let error {
37+
completion(.failure(error))
38+
}
39+
}
40+
}
41+
42+
private func queryParameters(from params: AllDomainsEndpointParams?) throws -> [String: AnyObject]? {
43+
guard let params else {
44+
return nil
45+
}
46+
let encoder = JSONEncoder()
47+
let data = try encoder.encode(params)
48+
let dict = try JSONSerialization.jsonObject(with: data) as? [String: AnyObject]
49+
return dict
50+
}
51+
52+
// MARK: - Public Types
53+
54+
public typealias AllDomainsEndpointResult = Result<[AllDomainsListItem], Error>
55+
56+
public struct AllDomainsEndpointParams {
57+
58+
public var resolveStatus: Bool = false
59+
public var noWPCOM: Bool = false
60+
public var locale: String?
61+
62+
public init() {}
63+
}
64+
65+
public struct AllDomainsListItem {
66+
67+
public enum StatusType: String {
68+
case success
69+
case premium
70+
case neutral
71+
case warning
72+
case alert
73+
case error
74+
}
75+
76+
public struct Status {
77+
78+
public let value: String
79+
public let type: StatusType
80+
81+
public init(value: String, type: StatusType) {
82+
self.value = value
83+
self.type = type
84+
}
85+
}
86+
87+
public let domain: String
88+
public let blogId: Int
89+
public let blogName: String
90+
public let type: DomainType
91+
public let isDomainOnlySite: Bool
92+
public let isWpcomStagingDomain: Bool
93+
public let hasRegistration: Bool
94+
public let registrationDate: Date?
95+
public let expiryDate: Date?
96+
public let wpcomDomain: Bool
97+
public let currentUserIsOwner: Bool?
98+
public let siteSlug: String
99+
public let status: Status?
100+
}
101+
102+
// MARK: - Private Types
103+
104+
private struct AllDomainsEndpointResponse: Decodable {
105+
let domains: [AllDomainsListItem]
106+
}
107+
}
108+
109+
// MARK: - Encoding / Decoding
110+
111+
extension DomainsServiceRemote.AllDomainsEndpointParams: Encodable {
112+
113+
enum CodingKeys: String, CodingKey {
114+
case resolveStatus = "resolve_status"
115+
case locale
116+
case noWPCOM = "no_wpcom"
117+
}
118+
119+
public func encode(to encoder: Encoder) throws {
120+
var container = encoder.container(keyedBy: CodingKeys.self)
121+
try container.encode("\(resolveStatus)", forKey: .resolveStatus)
122+
try container.encode("\(noWPCOM)", forKey: .noWPCOM)
123+
try container.encodeIfPresent(locale, forKey: .locale)
124+
}
125+
}
126+
127+
extension DomainsServiceRemote.AllDomainsListItem.StatusType: Decodable {
128+
}
129+
130+
extension DomainsServiceRemote.AllDomainsListItem.Status: Decodable {
131+
enum CodingKeys: String, CodingKey {
132+
case value = "status"
133+
case type = "status_type"
134+
}
135+
}
136+
137+
extension DomainsServiceRemote.AllDomainsListItem: Decodable {
138+
139+
enum CodingKeys: String, CodingKey {
140+
case domain
141+
case blogId = "blog_id"
142+
case blogName = "blog_name"
143+
case type
144+
case isDomainOnlySite = "is_domain_only_site"
145+
case isWpcomStagingDomain = "is_wpcom_staging_domain"
146+
case hasRegistration = "has_registration"
147+
case registrationDate = "registration_date"
148+
case expiryDate = "expiry"
149+
case wpcomDomain = "wpcom_domain"
150+
case currentUserIsOwner = "current_user_is_owner"
151+
case siteSlug = "site_slug"
152+
case status = "domain_status"
153+
}
154+
155+
public init(from decoder: Decoder) throws {
156+
let container = try decoder.container(keyedBy: CodingKeys.self)
157+
self.domain = try container.decode(String.self, forKey: .domain)
158+
self.blogId = try container.decode(Int.self, forKey: .blogId)
159+
self.blogName = try container.decode(String.self, forKey: .blogName)
160+
self.isDomainOnlySite = try container.decode(Bool.self, forKey: .isDomainOnlySite)
161+
self.isWpcomStagingDomain = try container.decode(Bool.self, forKey: .isWpcomStagingDomain)
162+
self.hasRegistration = try container.decode(Bool.self, forKey: .hasRegistration)
163+
self.wpcomDomain = try container.decode(Bool.self, forKey: .wpcomDomain)
164+
self.currentUserIsOwner = try container.decode(Bool?.self, forKey: .currentUserIsOwner)
165+
self.siteSlug = try container.decode(String.self, forKey: .siteSlug)
166+
self.registrationDate = try {
167+
if let timestamp = try? container.decodeIfPresent(String.self, forKey: .registrationDate), !timestamp.isEmpty {
168+
return try container.decode(Date.self, forKey: .registrationDate)
169+
}
170+
return nil
171+
}()
172+
self.expiryDate = try {
173+
if let timestamp = try? container.decodeIfPresent(String.self, forKey: .expiryDate), !timestamp.isEmpty {
174+
return try container.decode(Date.self, forKey: .expiryDate)
175+
}
176+
return nil
177+
}()
178+
let type: String = try container.decode(String.self, forKey: .type)
179+
self.type = .init(type: type, wpComDomain: wpcomDomain, hasRegistration: hasRegistration)
180+
self.status = try container.decodeIfPresent(Status.self, forKey: .status)
181+
}
182+
}

WordPressKit/RemoteDomain.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,26 @@ import Foundation
1818
return NSLocalizedString("Included with Site", comment: "Describes a standard *.wordpress.com site domain")
1919
}
2020
}
21+
22+
init(domainJson: [String: Any]) {
23+
self.init(
24+
type: domainJson["domain"] as? String,
25+
wpComDomain: domainJson["wpcom_domain"] as? Bool,
26+
hasRegistration: domainJson["has_registration"] as? Bool
27+
)
28+
}
29+
30+
init(type: String?, wpComDomain: Bool?, hasRegistration: Bool?) {
31+
if type == "redirect" {
32+
self = .siteRedirect
33+
} else if wpComDomain == true {
34+
self = .wpCom
35+
} else if hasRegistration == true {
36+
self = .registered
37+
} else {
38+
self = .mapped
39+
}
40+
}
2141
}
2242

2343
public struct RemoteDomain {

0 commit comments

Comments
 (0)