Skip to content
This repository was archived by the owner on Sep 15, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ _None._
### Breaking Changes

- Rewrite `WordPressOrgRestApi` to support self hosted sites and WordPress.com sites. [#724]
- Decouple `PluginDirectoryServiceRemote` from Alamofire. [#725]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- Decouple `PluginDirectoryServiceRemote` from Alamofire. [#725]
- Decouple `PluginDirectoryServiceRemote` from Alamofire. [#725]
- Remove `Endpoint`. [#725]

Endpoint might have been unused, but it was still a public type. Do you think it would be worth to track it in the changelog?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure thing. Added in dce3798.

- Remove `Endpoint`. [#725]

### New Features

Expand Down
4 changes: 0 additions & 4 deletions WordPressKit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -607,7 +607,6 @@
E14694031F344F71004052C8 /* site-plugins-error.json in Resources */ = {isa = PBXBuildFile; fileRef = E14694021F344F71004052C8 /* site-plugins-error.json */; };
E1787DB0200E564B004CB3AF /* timezones.json in Resources */ = {isa = PBXBuildFile; fileRef = E1787DAF200E564B004CB3AF /* timezones.json */; };
E1787DB2200E5690004CB3AF /* TimeZoneServiceRemoteTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1787DB1200E5690004CB3AF /* TimeZoneServiceRemoteTests.swift */; };
E182BF6A1FD961810001D850 /* Endpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = E182BF691FD961810001D850 /* Endpoint.swift */; };
E194CB731FBDEF6500B0A8B8 /* PluginState.swift in Sources */ = {isa = PBXBuildFile; fileRef = E194CB721FBDEF6400B0A8B8 /* PluginState.swift */; };
E1A6605F1FD694ED00BAC339 /* PluginDirectoryEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1A6605E1FD694ED00BAC339 /* PluginDirectoryEntry.swift */; };
E1BD95151FD5A2B800CD5CE3 /* PluginDirectoryServiceRemote.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1BD95141FD5A2B800CD5CE3 /* PluginDirectoryServiceRemote.swift */; };
Expand Down Expand Up @@ -1336,7 +1335,6 @@
E14694021F344F71004052C8 /* site-plugins-error.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "site-plugins-error.json"; sourceTree = "<group>"; };
E1787DAF200E564B004CB3AF /* timezones.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = timezones.json; sourceTree = "<group>"; };
E1787DB1200E5690004CB3AF /* TimeZoneServiceRemoteTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimeZoneServiceRemoteTests.swift; sourceTree = "<group>"; };
E182BF691FD961810001D850 /* Endpoint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Endpoint.swift; sourceTree = "<group>"; };
E194CB721FBDEF6400B0A8B8 /* PluginState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PluginState.swift; sourceTree = "<group>"; };
E1A6605E1FD694ED00BAC339 /* PluginDirectoryEntry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PluginDirectoryEntry.swift; sourceTree = "<group>"; };
E1BD95141FD5A2B800CD5CE3 /* PluginDirectoryServiceRemote.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PluginDirectoryServiceRemote.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1985,7 +1983,6 @@
74BA04F11F06DC0A00ED5CD8 /* CommentServiceRemoteXMLRPC.m */,
8BB5F62027A99A2000B2FFAF /* DashboardServiceRemote.swift */,
7E0D64FE22D855700092AD10 /* EditorServiceRemote.swift */,
E182BF691FD961810001D850 /* Endpoint.swift */,
F9E56DF724EB125600916770 /* FeatureFlagRemote.swift */,
74650F711F0EA1A700188EDB /* GravatarServiceRemote.swift */,
1769DEA924729AFF00F42EFC /* HomepageSettingsServiceRemote.swift */,
Expand Down Expand Up @@ -3462,7 +3459,6 @@
F1BB7806240FB90B0030ADDC /* AtomicAuthenticationServiceRemote.swift in Sources */,
404057CE221C38130060250C /* StatsTopVideosTimeIntervalData.swift in Sources */,
7E0D64FF22D855700092AD10 /* EditorServiceRemote.swift in Sources */,
E182BF6A1FD961810001D850 /* Endpoint.swift in Sources */,
9AF4F2FF2183346B00570E4B /* RemoteRevision.swift in Sources */,
17D936252475D8AB008B2205 /* RemoteHomepageType.swift in Sources */,
74BA04F41F06DC0A00ED5CD8 /* CommentServiceRemoteREST.m in Sources */,
Expand Down
55 changes: 0 additions & 55 deletions WordPressKit/Endpoint.swift

This file was deleted.

54 changes: 28 additions & 26 deletions WordPressKit/PluginDirectoryServiceRemote.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import Foundation
import Alamofire

private struct PluginDirectoryRemoteConstants {
static let dateFormatter: DateFormatter = {
Expand Down Expand Up @@ -47,7 +46,7 @@ public enum PluginDirectoryFeedType: Hashable {
}
}

public struct PluginDirectoryGetInformationEndpoint: Endpoint {
public struct PluginDirectoryGetInformationEndpoint {
public enum Error: Swift.Error {
case pluginNotFound
}
Expand All @@ -57,20 +56,18 @@ public struct PluginDirectoryGetInformationEndpoint: Endpoint {
self.slug = slug
}

public func buildRequest() throws -> URLRequest {
let url = PluginDirectoryRemoteConstants.getInformationEndpoint
.appendingPathComponent(slug)
.appendingPathExtension("json")
let request = URLRequest(url: url)
let encodedRequest = try URLEncoding.default.encode(request, with: ["fields": "icons,banners"])
return encodedRequest
func buildRequest() throws -> URLRequest {
try HTTPRequestBuilder(url: PluginDirectoryRemoteConstants.getInformationEndpoint)
.append(percentEncodedPath: "\(slug).json")
.query(name: "fields", value: "icons,banners")
.build()
}

public func parseResponse(data: Data) throws -> PluginDirectoryEntry {
func parseResponse(data: Data) throws -> PluginDirectoryEntry {
return try PluginDirectoryRemoteConstants.jsonDecoder.decode(PluginDirectoryEntry.self, from: data)
}

public func validate(request: URLRequest?, response: HTTPURLResponse, data: Data?) throws {
func validate(response: HTTPURLResponse, data: Data?) throws {
// api.wordpress.org has an odd way of responding to plugin info requests for
// plugins not in the directory: it will return `null` with an HTTP 200 OK.
// This turns that case into a `.pluginNotFound` error.
Expand All @@ -83,20 +80,20 @@ public struct PluginDirectoryGetInformationEndpoint: Endpoint {
}
}

public struct PluginDirectoryFeedEndpoint: Endpoint {
public struct PluginDirectoryFeedEndpoint {
public enum Error: Swift.Error {
case genericError
}

let feedType: PluginDirectoryFeedType
let pageNumber: Int

public init(feedType: PluginDirectoryFeedType) {
init(feedType: PluginDirectoryFeedType) {
self.feedType = feedType
self.pageNumber = 1
}

public func buildRequest() throws -> URLRequest {
func buildRequest() throws -> URLRequest {
var parameters: [String: Any] = ["action": "query_plugins",
"request[per_page]": PluginDirectoryRemoteConstants.pluginsPerPage,
"request[fields][icons]": 1,
Expand All @@ -113,17 +110,16 @@ public struct PluginDirectoryFeedEndpoint: Endpoint {

}

let request = URLRequest(url: PluginDirectoryRemoteConstants.feedEndpoint)
let encodedRequest = try URLEncoding.default.encode(request, with: parameters)

return encodedRequest
return try HTTPRequestBuilder(url: PluginDirectoryRemoteConstants.feedEndpoint)
.query(parameters)
.build()
}

public func parseResponse(data: Data) throws -> PluginDirectoryFeedPage {
func parseResponse(data: Data) throws -> PluginDirectoryFeedPage {
return try PluginDirectoryRemoteConstants.jsonDecoder.decode(PluginDirectoryFeedPage.self, from: data)
}

public func validate(request: URLRequest?, response: HTTPURLResponse, data: Data?) throws {
func validate(response: HTTPURLResponse, data: Data?) throws {
if response.statusCode != 200 { throw Error.genericError}
}
}
Expand All @@ -132,13 +128,19 @@ public struct PluginDirectoryServiceRemote {

public init() {}

public func getPluginFeed(_ feedType: PluginDirectoryFeedType,
pageNumber: Int = 1,
completion: @escaping (Result<PluginDirectoryFeedPage>) -> Void) {
PluginDirectoryFeedEndpoint(feedType: feedType).request(completion: completion)
public func getPluginFeed(_ feedType: PluginDirectoryFeedType, pageNumber: Int = 1) async throws -> PluginDirectoryFeedPage {
let endpoint = PluginDirectoryFeedEndpoint(feedType: feedType)
let (data, response) = try await URLSession.shared.data(for: endpoint.buildRequest())
let httpResponse = response as! HTTPURLResponse
try endpoint.validate(response: httpResponse, data: data)
return try endpoint.parseResponse(data: data)
}

public func getPluginInformation(slug: String, completion: @escaping (Result<PluginDirectoryEntry>) -> Void) {
PluginDirectoryGetInformationEndpoint(slug: slug).request(completion: completion)
public func getPluginInformation(slug: String) async throws -> PluginDirectoryEntry {
let endpoint = PluginDirectoryGetInformationEndpoint(slug: slug)
let (data, response) = try await URLSession.shared.data(for: endpoint.buildRequest())
let httpResponse = response as! HTTPURLResponse
try endpoint.validate(response: httpResponse, data: data)
return try endpoint.parseResponse(data: data)
}
}
29 changes: 25 additions & 4 deletions WordPressKitTests/PluginDirectoryTests.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import XCTest
import OHHTTPStubs
@testable import WordPressKit

class PluginDirectoryTests: XCTestCase {
Expand Down Expand Up @@ -51,13 +52,33 @@ class PluginDirectoryTests: XCTestCase {
}
}

func testGetPluginInformation() async throws {
let data = try MockPluginDirectoryProvider.getPluginDirectoryMockData(with: "plugin-directory-rename-xml-rpc", sender: type(of: self))
stub(condition: isHost("api.wordpress.org")) { _ in
HTTPStubsResponse(data: data, statusCode: 200, headers: ["Content-Type": "application/json"])
}

let plugin = try await PluginDirectoryServiceRemote().getPluginInformation(slug: "rename-xml-rpc")
XCTAssertEqual(plugin.name, "Rename XMLRPC")
}

func testGetDirectoryFeed() async throws {
let data = try MockPluginDirectoryProvider.getPluginDirectoryMockData(with: "plugin-directory-popular", sender: type(of: self))
stub(condition: isHost("api.wordpress.org")) { _ in
HTTPStubsResponse(data: data, statusCode: 200, headers: ["Content-Type": "application/json"])
}

let feed = try await PluginDirectoryServiceRemote().getPluginFeed(.popular)
XCTAssertEqual(feed.plugins.first?.name, "Contact Form 7")
}

func testValidateResponseFound() {
let data = try! MockPluginDirectoryProvider.getPluginDirectoryMockData(with: "plugin-directory-rename-xml-rpc", sender: type(of: self))
let endpoint = PluginDirectoryGetInformationEndpoint(slug: "jetpack")
do {
let request = try endpoint.buildRequest()
let response = HTTPURLResponse(url: request.url!, statusCode: 200, httpVersion: "1.1", headerFields: nil)!
XCTAssertNoThrow(try endpoint.validate(request: request, response: response, data: data))
XCTAssertNoThrow(try endpoint.validate(response: response, data: data))
} catch {
XCTFail(error.localizedDescription)
}
Expand All @@ -70,7 +91,7 @@ class PluginDirectoryTests: XCTestCase {
let request = try! endpoint.buildRequest()
let response = HTTPURLResponse(url: request.url!, statusCode: 200, httpVersion: "1.1", headerFields: nil)!

XCTAssertThrowsError(try endpoint.validate(request: request, response: response, data: "null".data(using: .utf8)))
XCTAssertThrowsError(try endpoint.validate(response: response, data: "null".data(using: .utf8)))
}

func testValidatePluginDirectoryFeedResponseSucceeds() throws {
Expand All @@ -79,7 +100,7 @@ class PluginDirectoryTests: XCTestCase {
let request = try endpoint.buildRequest()
let response = HTTPURLResponse(url: request.url!, statusCode: 200, httpVersion: "1.1", headerFields: nil)!

XCTAssertNoThrow(try endpoint.validate(request: request, response: response, data: "null".data(using: .utf8)))
XCTAssertNoThrow(try endpoint.validate(response: response, data: "null".data(using: .utf8)))
}

func testValidatePluginDirectoryFeedResponseFails() {
Expand All @@ -88,7 +109,7 @@ class PluginDirectoryTests: XCTestCase {
let request = try! endpoint.buildRequest()
let response = HTTPURLResponse(url: request.url!, statusCode: 403, httpVersion: "1.1", headerFields: nil)!

XCTAssertThrowsError(try endpoint.validate(request: request, response: response, data: "null".data(using: .utf8)))
XCTAssertThrowsError(try endpoint.validate(response: response, data: "null".data(using: .utf8)))
}

func testNewDirectoryFeedRequest() {
Expand Down