Skip to content

Commit

Permalink
Merge branch 'develop' into chore/bump-avs-9.10-WPB-11904-cherry-pick
Browse files Browse the repository at this point in the history
  • Loading branch information
caldrian authored Nov 27, 2024
2 parents c2c89c9 + 4b2b398 commit eea43f0
Show file tree
Hide file tree
Showing 119 changed files with 6,504 additions and 3,234 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,12 @@ public protocol ConversationsAPI {
in domain: String
) async throws -> Conversation

/// Fetches the guest link for a given conversation.
/// - parameter conversationID: The conversation identifier.
/// - returns: The conversation guest link.

func getConversationGuestLink(
conversationID: String
) async throws -> String?

}
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,14 @@ import Foundation
/// Builder for the conversations API.
public struct ConversationsAPIBuilder {

private let httpClient: any HTTPClient
let apiService: any APIServiceProtocol

/// Create a new builder for the conversations API.
/// Create a new builder.
///
/// - Parameter httpClient: A http client.
public init(httpClient: any HTTPClient) {
self.httpClient = httpClient
/// - Parameter APIService: An api service.

public init(apiService: any APIServiceProtocol) {
self.apiService = apiService
}

/// Make a versioned `ConversationsAPI`.
Expand All @@ -37,19 +38,19 @@ public struct ConversationsAPIBuilder {
public func makeAPI(for version: APIVersion) -> any ConversationsAPI {
switch version {
case .v0:
ConversationsAPIV0(httpClient: httpClient)
ConversationsAPIV0(apiService: apiService)
case .v1:
ConversationsAPIV1(httpClient: httpClient)
ConversationsAPIV1(apiService: apiService)
case .v2:
ConversationsAPIV2(httpClient: httpClient)
ConversationsAPIV2(apiService: apiService)
case .v3:
ConversationsAPIV3(httpClient: httpClient)
ConversationsAPIV3(apiService: apiService)
case .v4:
ConversationsAPIV4(httpClient: httpClient)
ConversationsAPIV4(apiService: apiService)
case .v5:
ConversationsAPIV5(httpClient: httpClient)
ConversationsAPIV5(apiService: apiService)
case .v6:
ConversationsAPIV6(httpClient: httpClient)
ConversationsAPIV6(apiService: apiService)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
/// Errors originating from `ConversationsAPI`.
public enum ConversationsAPIError: Error {

/// A request url is not invalid.
case invalidURL

/// Failure if functionality has not been implemented.
case notImplemented

Expand All @@ -37,4 +40,19 @@ public enum ConversationsAPIError: Error {
/// Failure if user and domain are empty
case userAndDomainShouldNotBeEmpty

/// Access denied
case accessDenied

/// Conversation not found
case conversationNotFound

/// Conversation code not found
case conversationCodeNotFound

/// Conversation guests links disabled
case guestLinksDisabled

/// Invalid conversation id
case invalidConversationID

}
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,18 @@ class ConversationsAPIV0: ConversationsAPI, VersionedAPI {

// MARK: - Properties

let apiService: any APIServiceProtocol

var apiVersion: APIVersion { .v0 }

let httpClient: any HTTPClient
var basePath: String {
"/conversations"
}

// MARK: - Initialize

init(httpClient: any HTTPClient) {
self.httpClient = httpClient
init(apiService: any APIServiceProtocol) {
self.apiService = apiService
}

func getLegacyConversationIdentifiers() async throws -> PayloadPager<UUID> {
Expand All @@ -48,24 +52,32 @@ class ConversationsAPIV0: ConversationsAPI, VersionedAPI {
// As soon as APIVersion.v0 is removed, the legacy function can be deleted, making the code clean and easy to
// understand.

let resourcePath = "/conversations/list-ids/"
let components = URLComponents(string: "\(basePath)/list-ids/")
let jsonEncoder = JSONEncoder.defaultEncoder

guard let url = components?.url else {
assertionFailure("generated an invalid url")
throw ConversationsAPIError.invalidURL
}

return PayloadPager<UUID> { start in
// body Params
let params = PaginationRequest(pagingState: start, size: Constants.batchSize)
let body = try jsonEncoder.encode(params)

let request = HTTPRequest(
path: resourcePath,
method: .post,
body: body
let request = URLRequestBuilder(url: url)
.withMethod(.post)
.withBody(body, contentType: .json)
.build()

let (data, response) = try await self.apiService.executeRequest(
request,
requiringAccessToken: true
)
let response = try await self.httpClient.executeRequest(request)

return try ResponseParser()
.success(code: .ok, type: PaginatedConversationIDsV0.self)
.parse(response)
.parse(code: response.statusCode, data: data)
}
}

Expand All @@ -77,19 +89,27 @@ class ConversationsAPIV0: ConversationsAPI, VersionedAPI {
func getConversations(for identifiers: [QualifiedID]) async throws -> ConversationList {
let parameters = GetConversationsParametersV0(qualifiedIdentifiers: identifiers)
let body = try JSONEncoder.defaultEncoder.encode(parameters)

Check warning on line 91 in WireAPI/Sources/WireAPI/APIs/ConversationsAPI/ConversationsAPIV0.swift

View workflow job for this annotation

GitHub Actions / Test Results

Variable 'components' was never mutated; consider changing to 'let' constant

Variable 'components' was never mutated; consider changing to 'let' constant
let resourcePath = "\(pathPrefix)/conversations/list/v2"
var components = URLComponents(string: "\(pathPrefix)\(basePath)/list/v2")

guard let url = components?.url else {
assertionFailure("generated an invalid url")
throw ConversationsAPIError.invalidURL
}

let request = URLRequestBuilder(url: url)
.withMethod(.post)
.withBody(body, contentType: .json)
.build()

let request = HTTPRequest(
path: resourcePath,
method: .post,
body: body
let (data, response) = try await apiService.executeRequest(
request,
requiringAccessToken: true
)
let response = try await httpClient.executeRequest(request)

return try ResponseParser()
.success(code: .ok, type: QualifiedConversationListV0.self)
.failure(code: .badRequest, error: ConversationsAPIError.invalidBody)
.parse(response)
.parse(code: response.statusCode, data: data)
}

func getMLSOneToOneConversation(
Expand All @@ -98,6 +118,40 @@ class ConversationsAPIV0: ConversationsAPI, VersionedAPI {
) async throws -> Conversation {
throw ConversationsAPIError.unsupportedEndpointForAPIVersion
}

func getConversationGuestLink(
conversationID: String
) async throws -> String? {
let components = URLComponents(string: "\(pathPrefix)\(basePath)/\(conversationID)/code")

guard let url = components?.url else {
assertionFailure("generated an invalid url")
throw ConversationsAPIError.invalidURL
}

let request = URLRequestBuilder(url: url)
.withMethod(.get)
.build()

let (data, response) = try await apiService.executeRequest(
request,
requiringAccessToken: true
)

return try ResponseParser()
.success(code: .ok, type: ConversationCodeV0.self)
.failure(code: .forbidden, label: "access-denied", error: ConversationsAPIError.accessDenied)
.failure(code: .notFound, label: "cnv", error: ConversationsAPIError.invalidConversationID)
.failure(code: .notFound, label: "no-conversation", error: ConversationsAPIError.conversationNotFound)
.failure(
code: .notFound,
label: "no-conversation-code",
error: ConversationsAPIError.conversationCodeNotFound
)
.failure(code: .conflict, label: "guest-links-disabled", error: ConversationsAPIError.guestLinksDisabled)
.parse(code: response.statusCode, data: data)
}

}

// MARK: Encodables
Expand Down Expand Up @@ -220,3 +274,14 @@ struct ConversationV0: Decodable, ToAPIModelConvertible {
)
}
}

struct ConversationCodeV0: Decodable, ToAPIModelConvertible {

let code: String
let key: String
let uri: String?

func toAPIModel() -> String? {
uri
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,24 +27,32 @@ class ConversationsAPIV1: ConversationsAPIV0 {
}

override func getConversationIdentifiers() async throws -> PayloadPager<QualifiedID> {
let resourcePath = "\(pathPrefix)/conversations/list-ids/"
let components = URLComponents(string: "\(pathPrefix)\(basePath)/list-ids/")
let jsonEncoder = JSONEncoder.defaultEncoder

guard let url = components?.url else {
assertionFailure("generated an invalid url")
throw ConversationsAPIError.invalidURL
}

return PayloadPager<QualifiedID> { start in
// body Params
let params = PaginationRequest(pagingState: start, size: Constants.batchSize)
let body = try jsonEncoder.encode(params)

let request = HTTPRequest(
path: resourcePath,
method: .post,
body: body
let request = URLRequestBuilder(url: url)
.withMethod(.post)
.withBody(body, contentType: .json)
.build()

let (data, response) = try await self.apiService.executeRequest(
request,
requiringAccessToken: true
)
let response = try await self.httpClient.executeRequest(request)

return try ResponseParser()
.success(code: .ok, type: PaginatedConversationIDsV1.self)
.parse(response)
.parse(code: response.statusCode, data: data)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,26 @@ class ConversationsAPIV2: ConversationsAPIV1 {
let body = try JSONEncoder.defaultEncoder.encode(parameters)

// New change for v2
let resourcePath = "\(pathPrefix)/conversations/list"
let components = URLComponents(string: "\(pathPrefix)\(basePath)/list")

let request = HTTPRequest(
path: resourcePath,
method: .post,
body: body
guard let url = components?.url else {
assertionFailure("generated an invalid url")
throw ConversationsAPIError.invalidURL
}

let request = URLRequestBuilder(url: url)
.withMethod(.post)
.withBody(body, contentType: .json)
.build()

let (data, response) = try await apiService.executeRequest(
request,
requiringAccessToken: true
)
let response = try await httpClient.executeRequest(request)

return try ResponseParser()
.success(code: .ok, type: QualifiedConversationListV0.self)
.failure(code: .badRequest, error: ConversationsAPIError.invalidBody)
.parse(response)
.parse(code: response.statusCode, data: data)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,28 @@ class ConversationsAPIV3: ConversationsAPIV2 {
override func getConversations(for identifiers: [QualifiedID]) async throws -> ConversationList {
let parameters = GetConversationsParametersV0(qualifiedIdentifiers: identifiers)
let body = try JSONEncoder.defaultEncoder.encode(parameters)
let resourcePath = "\(pathPrefix)/conversations/list"

let request = HTTPRequest(
path: resourcePath,
method: .post,
body: body
let components = URLComponents(string: "\(pathPrefix)\(basePath)/list")

guard let url = components?.url else {
assertionFailure("generated an invalid url")
throw ConversationsAPIError.invalidURL
}

let request = URLRequestBuilder(url: url)
.withMethod(.post)
.withBody(body, contentType: .json)
.build()

let (data, response) = try await apiService.executeRequest(
request,
requiringAccessToken: true
)
let response = try await httpClient.executeRequest(request)

return try ResponseParser()
.success(code: .ok, type: QualifiedConversationListV3.self) // Change in v3
.failure(code: .badRequest, error: ConversationsAPIError.invalidBody)
.parse(response)
.parse(code: response.statusCode, data: data)
}
}

Expand Down
Loading

0 comments on commit eea43f0

Please sign in to comment.