Skip to content

Commit

Permalink
Merge pull request #4 from skelpo/develop
Browse files Browse the repository at this point in the history
Version 0.2.0
  • Loading branch information
calebkleveter authored Dec 3, 2018
2 parents 176d506 + b0e6445 commit c4b0d39
Show file tree
Hide file tree
Showing 184 changed files with 4,483 additions and 2,151 deletions.
30 changes: 21 additions & 9 deletions Sources/PayPal/API/Controller.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,18 @@ public protocol PayPalController: ServiceType {
/// The API resource that the controller connects to.
var resource: String { get }

/// The version of the PayPal API to use when making request's to the API.
///
/// Defaults to `.v1`.
var version: Version { get }

/// Creates an instance of the controller on a given container.
///
/// Instead of directly initializing the controller, you should register
/// the provider and get the controller using `container.make(Controller.self)`.
///
/// - Parameter container: The container that the controller belongs to.
init(container: Container)

/// The controller's path used on the PayPal API.
///
/// The default value is `v{Configuration.version}/{resource}/`.
func path()throws -> String
}

extension PayPalController {
Expand All @@ -31,10 +31,22 @@ extension PayPalController {
}

/// The controller's path used on the PayPal API.
public var path: String {
return "v" + self.version.rawValue + "/" + resource + "/"
}

/// Fetches the registered `PayPalClient` instance from the container and makes it
/// availible in a closure, so any errors that are thrown can be caught and returned in the resulting future.
///
/// - Parameter closure: The closure you have access to the `PayPalClient` in.
///
/// The default value is `v{Configuration.version}/{resource}/`.
public func path()throws -> String {
let config = try self.container.make(Configuration.self)
return "v" + config.version + "/" + resource + "/"
/// - Returns: The future returned from the closure passed in.
public func client<T>(_ closure: (PayPalClient)throws -> (Future<T>)) -> Future<T> {
do {
let client = try self.container.make(PayPalClient.self)
return try closure(client)
} catch let error {
return self.container.future(error: error)
}
}
}
11 changes: 7 additions & 4 deletions Sources/PayPal/API/Controllers/Activities.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,14 @@ public final class Activities: PayPalController {
/// See `PayPalController.resource`.
public let resource: String

/// See `PayPalController.version`.
public let version: Version

/// See `PayPalController.init(container:)`.
public init(container: Container) {
self.container = container
self.resource = "activities"
self.version = try container.make(Configuration.self).version || .v1
}

/// Sends a request to the PayPal `GET /v{Configuration.version}/activities/activities` endpoint.
Expand All @@ -27,10 +31,9 @@ public final class Activities: PayPalController {
///
/// - Parameter parameters: The querys string parameters to send in the request URL.
/// - Returns: The endpoint's response, decoded to an `ActivitiesResponse` object, wrapped in a future.
public func activities(parameters: QueryParamaters = QueryParamaters()) -> Future<ActivitiesResponse> {
return Future.flatMap(on: self.container) { () -> Future<ActivitiesResponse> in
let client = try self.container.make(PayPalClient.self)
return try client.get(self.path() + "activities", parameters: parameters)
public func activities(parameters: QueryParamaters = QueryParamaters()) -> Future<Activity.Response> {
return self.client { client in
return client.get(self.path + "activities", parameters: parameters)
}
}
}
59 changes: 25 additions & 34 deletions Sources/PayPal/API/Controllers/BillingAgreements.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,14 @@ public final class BillingAgreements: PayPalController {
/// See `PayPalController.resource` for more information.
public let resource: String

/// See `PayPalController.version`.
public let version: Version

/// See `PayPalController.init(container:)`.
public init(container: Container) {
self.container = container
self.resource = "payments//billing-agreements"
self.version = try container.make(Configuration.self).version || .v1
}

/// Creates a billing agreement.
Expand All @@ -39,9 +43,8 @@ public final class BillingAgreements: PayPalController {
/// - Returns: The billing agreement that was created, wrapped in a future. If an error occured
/// while creating the agreement, that is wrapped in the future instead.
public func create(with agreement: NewAgreement) -> Future<BillingAgreement> {
return Future.flatMap(on: container) { () -> Future<BillingAgreement> in
let client = try self.container.make(PayPalClient.self)
return try client.post(self.path(), body: agreement, as: BillingAgreement.self)
return self.client { client in
return client.post(self.path, body: agreement, as: BillingAgreement.self)
}
}

Expand All @@ -56,9 +59,8 @@ public final class BillingAgreements: PayPalController {
/// - Returns: The HTTP status code of the response, which will be 200. If an error was returned in the
/// response, it will get conveted to a Swift error and be returned in the future instead.
public func update(agreement id: String, with patches: [Patch]) -> Future<HTTPStatus> {
return Future.flatMap(on: self.container) { () -> Future<HTTPStatus> in
let client = try self.container.make(PayPalClient.self)
return try client.patch(self.path() + id, body: ["patch_request": patches], as: HTTPStatus.self)
return self.client { client in
return client.patch(self.path + id, body: ["patch_request": patches], as: HTTPStatus.self)
}
}

Expand All @@ -73,9 +75,8 @@ public final class BillingAgreements: PayPalController {
/// If an error is returned in the response, it is converted to a Swift error
/// and is tha value that the future wraps instead.
public func get(agreement id: String) -> Future<BillingAgreement> {
return Future.flatMap(on: self.container) { () -> Future<BillingAgreement> in
let client = try self.container.make(PayPalClient.self)
return try client.get(self.path() + id, as: BillingAgreement.self)
return self.client { client in
return client.get(self.path + id, as: BillingAgreement.self)
}
}

Expand All @@ -91,13 +92,11 @@ public final class BillingAgreements: PayPalController {
/// - Returns: The HTTP status code of the response, which will be 204. If an error was returned in the
/// response, it will get conveted to a Swift error and be returned in the future instead.
public func billBalance(for agreementID: String, reason: String?) -> Future<HTTPStatus> {
return Future.flatMap(on: self.container) { () -> Future<HTTPStatus> in
return self.client { client in
guard reason?.count ?? 0 <= 128 else {
throw PayPalError(status: .badRequest, identifier: "invalidLength", reason: "`note` property must have a length of 128 or less")
}

let client = try self.container.make(PayPalClient.self)
return try client.post(self.path() + agreementID + "/bill-balance", body: ["note": reason], as: HTTPStatus.self)
return client.post(self.path + agreementID + "/bill-balance", body: ["note": reason], as: HTTPStatus.self)
}
}

Expand All @@ -113,13 +112,11 @@ public final class BillingAgreements: PayPalController {
/// - Returns: The HTTP status code of the response, which will be 204. If an error was returned in the
/// response, it will get conveted to a Swift error and be returned in the future instead.
public func cancel(agreement id: String, reason: String?) -> Future<HTTPStatus> {
return Future.flatMap(on: self.container) { () -> Future<HTTPStatus> in
return self.client { client in
guard reason?.count ?? 0 <= 128 else {
throw PayPalError(status: .badRequest, identifier: "invalidLength", reason: "`note` property must have a length of 128 or less")
}

let client = try self.container.make(PayPalClient.self)
return try client.post(self.path() + id + "/cancel", body: ["note": reason], as: HTTPStatus.self)
return client.post(self.path + id + "/cancel", body: ["note": reason], as: HTTPStatus.self)
}
}

Expand All @@ -135,13 +132,12 @@ public final class BillingAgreements: PayPalController {
/// - Returns: The HTTP status code of the API response, which will be `204`. If an error was returned in the
/// response, it will get conveted to a Swift error and be returned in the future instead.
public func reactivate(agreement id: String, reason: String?) -> Future<HTTPStatus> {
return Future.flatMap(on: self.container) { () -> Future<HTTPStatus> in
return self.client { client in
guard reason?.count ?? 0 <= 128 else {
throw PayPalError(status: .badRequest, identifier: "invalidLength", reason: "`note` property must have a length of 128 or less")
}

let client = try self.container.make(PayPalClient.self)
return try client.post(self.path() + id + "/re-activate", body: ["note": reason], as: HTTPStatus.self)
return client.post(self.path + id + "/re-activate", body: ["note": reason], as: HTTPStatus.self)
}
}

Expand All @@ -155,10 +151,9 @@ public final class BillingAgreements: PayPalController {
///
/// - Returns: The HTTP status code of the API response, which will be `204`. If an error was returned in the
/// response, it will get conveted to a Swift error and be returned in the future instead.
public func setBalance(for agreementID: String, amount: Money) -> Future<HTTPStatus> {
return Future.flatMap(on: self.container) { () -> Future<HTTPStatus> in
let client = try self.container.make(PayPalClient.self)
return try client.post(self.path() + agreementID + "/set-balance", body: amount, as: HTTPStatus.self)
public func setBalance(for agreementID: String, amount: CurrencyCodeAmount) -> Future<HTTPStatus> {
return self.client { client in
return client.post(self.path + agreementID + "/set-balance", body: amount, as: HTTPStatus.self)
}
}

Expand All @@ -173,13 +168,11 @@ public final class BillingAgreements: PayPalController {
/// - Returns: The HTTP status code of the API response, which will be `204`. If an error was returned in the
/// response, it will get conveted to a Swift error and be returned in the future instead.
public func suspend(agreement id: String, reason: String?) -> Future<HTTPStatus> {
return Future.flatMap(on: self.container) { () -> Future<HTTPStatus> in
return self.client { client in
guard reason?.count ?? 0 <= 128 else {
throw PayPalError(status: .badRequest, identifier: "invalidLength", reason: "`note` property must have a length of 128 or less")
}

let client = try self.container.make(PayPalClient.self)
return try client.post(self.path() + id + "/suspend", body: ["note": reason], as: HTTPStatus.self)
return client.post(self.path + id + "/suspend", body: ["note": reason], as: HTTPStatus.self)
}
}

Expand All @@ -196,9 +189,8 @@ public final class BillingAgreements: PayPalController {
/// - Returns: An array of transactions for the billing agreement within the time periods set in the query paramaters.
/// If an error was found in the response, it is converted to a Swift error and that is what the future wraps instead.
public func transactions(for agreementID: String, parameters: QueryParamaters = QueryParamaters()) -> Future<[Transaction]> {
return Future.flatMap(on: self.container) { () -> Future<[Transaction]> in
let client = try self.container.make(PayPalClient.self)
return try client.get(self.path() + agreementID + "/transactions", parameters: parameters, as: [Transaction].self)
return self.client { client in
return client.get(self.path + agreementID + "/transactions", parameters: parameters, as: [Transaction].self)
}
}

Expand All @@ -211,9 +203,8 @@ public final class BillingAgreements: PayPalController {
/// - Returns: The billing agreement object that was executed wrapped in a future.
/// If an error was found in the response, it is converted to a Swift error and that is what the future wraps instead.
public func execute(agreement id: String) -> Future<BillingAgreement> {
return Future.flatMap(on: self.container) { () -> Future<BillingAgreement> in
let client = try self.container.make(PayPalClient.self)
return try client.post(self.path() + id + "/agreement-execute", as: BillingAgreement.self)
return self.client { client in
return client.post(self.path + id + "/agreement-execute", as: BillingAgreement.self)
}
}
}
31 changes: 14 additions & 17 deletions Sources/PayPal/API/Controllers/BillingPlans.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,14 @@ public final class BillingPlans: PayPalController {
/// See `PayPalController.resource` for more information.
public let resource: String

/// See `PayPalController.version`.
public let version: Version

/// See `PayPalController.init(container:)`.
public init(container: Container) {
self.container = container
self.resource = "payments/billing-plans"
self.version = try container.make(Configuration.self).version || .v1
}


Expand All @@ -46,11 +50,9 @@ public final class BillingPlans: PayPalController {
/// - Returns: The created billing plan wrapped in a future. If an error response was sent back instead, it gets converted
/// to a Swift error and the future wraps that instead.
public func create(with plan: BillingPlan) -> Future<BillingPlan> {
return Future.flatMap(on: self.container) { () -> Future<BillingPlan> in
return self.client { client in
guard plan.type != nil else { throw PayPalError(identifier: "nilValue", reason: "BillingPlan `type` value must not be `nil`.") }

let client = try self.container.make(PayPalClient.self)
return try client.post(self.path(), body: plan, as: BillingPlan.self)
return client.post(self.path, body: plan, as: BillingPlan.self)
}
}

Expand All @@ -65,17 +67,16 @@ public final class BillingPlans: PayPalController {
///
/// - Returns: A list of the billing plans wrapped in a future. If an error response was sent back instead, it gets converted
/// to a Swift error and the future wraps that instead.
public func list(state: BillingPlan.State? = nil, parameters: QueryParamaters = QueryParamaters()) -> Future<BillingPlanList> {
return Future.flatMap(on: self.container) { () -> Future<BillingPlanList> in
let client = try self.container.make(PayPalClient.self)
public func list(state: BillingPlan.State? = nil, parameters: QueryParamaters = QueryParamaters()) -> Future<BillingPlan.List> {
return self.client { client in
var params = parameters

if let state = state, params.custom == nil {
params.custom = ["status": state.rawValue]
} else {
params.custom?["status"] = state?.rawValue
}
return try client.get(self.path(), parameters: params, as: BillingPlanList.self)
return client.get(self.path, parameters: params, as: BillingPlan.List.self)
}
}

Expand All @@ -91,9 +92,8 @@ public final class BillingPlans: PayPalController {
/// - Returns: The HTTP status of the response, in this case `200 OK`. If an error response was sent back instead,
/// it gets converted to a Swift error and the future wraps that instead.
public func update(plan id: String, patches: [Patch]) -> Future<HTTPStatus> {
return Future.flatMap(on: self.container) { () -> Future<HTTPStatus> in
let client = try self.container.make(PayPalClient.self)
return try client.patch(self.path() + id, body: patches, as: HTTPStatus.self)
return self.client { client in
return client.patch(self.path + id, body: patches, as: HTTPStatus.self)
}
}

Expand All @@ -106,9 +106,8 @@ public final class BillingPlans: PayPalController {
/// - Returns: The billing plan for the ID passed in, wrapped in a future. If an error response was sent back instead,
/// it gets converted to a Swift error and the future wraps that instead.
public func details(plan id: String) -> Future<BillingPlan> {
return Future.flatMap(on: self.container) { () -> Future<BillingPlan> in
let client = try self.container.make(PayPalClient.self)
return try client.get(self.path() + id, as: BillingPlan.self)
return self.client { client in
return client.get(self.path + id, as: BillingPlan.self)
}
}

Expand All @@ -124,8 +123,6 @@ public final class BillingPlans: PayPalController {
/// it gets converted to a Swift error and the future wraps that instead.
public func setState(of planID: String, to state: BillingPlan.State) -> Future<HTTPStatus> {
let newValue = JSON.object(["state": .string(state.rawValue)])
return self.update(plan: planID, patches: [
Patch(operation: .replace, path: "/", value: newValue)
])
return self.update(plan: planID, patches: [ Patch(operation: .replace, path: "/", value: newValue) ])
}
}
Loading

0 comments on commit c4b0d39

Please sign in to comment.