Skip to content

Commit

Permalink
add ValidateCheckout query support (#1938)
Browse files Browse the repository at this point in the history
  • Loading branch information
scottkicks committed Feb 8, 2024
1 parent 69a08e4 commit 0d5974b
Show file tree
Hide file tree
Showing 7 changed files with 244 additions and 0 deletions.
8 changes: 8 additions & 0 deletions Kickstarter.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,8 @@
6080DA402AB366680088EF3D /* Text+HTML.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6080DA3F2AB366680088EF3D /* Text+HTML.swift */; };
608E7A5328ABDBAE00289E92 /* SetYourPasswordViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 608E7A5128ABD5E700289E92 /* SetYourPasswordViewController.swift */; };
608E7A5628ABE6CD00289E92 /* SetYourPasswordViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 608E7A5428ABE27400289E92 /* SetYourPasswordViewModel.swift */; };
608F974A2B7522EF00DBE7D7 /* ValidateCheckout.graphql in Resources */ = {isa = PBXBuildFile; fileRef = 608F97492B7522EF00DBE7D7 /* ValidateCheckout.graphql */; };
608F974C2B752C4900DBE7D7 /* ValidateCheckoutEnvelope.swift in Sources */ = {isa = PBXBuildFile; fileRef = 608F974B2B752C4900DBE7D7 /* ValidateCheckoutEnvelope.swift */; };
6093098D2A6054CB004297AF /* GraphAPI.TriggerThirdPartyEventInput+TriggerThirdPartyEventInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6093098C2A6054CB004297AF /* GraphAPI.TriggerThirdPartyEventInput+TriggerThirdPartyEventInput.swift */; };
609309912A60555F004297AF /* TriggerThirdPartyEventInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 609309902A60555F004297AF /* TriggerThirdPartyEventInput.swift */; };
609309952A6055A5004297AF /* TriggerThirdPartyEvent.graphql in Resources */ = {isa = PBXBuildFile; fileRef = 609309942A6055A5004297AF /* TriggerThirdPartyEvent.graphql */; };
Expand Down Expand Up @@ -2043,6 +2045,8 @@
6080DA3F2AB366680088EF3D /* Text+HTML.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Text+HTML.swift"; sourceTree = "<group>"; };
608E7A5128ABD5E700289E92 /* SetYourPasswordViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetYourPasswordViewController.swift; sourceTree = "<group>"; };
608E7A5428ABE27400289E92 /* SetYourPasswordViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetYourPasswordViewModel.swift; sourceTree = "<group>"; };
608F97492B7522EF00DBE7D7 /* ValidateCheckout.graphql */ = {isa = PBXFileReference; lastKnownFileType = text; path = ValidateCheckout.graphql; sourceTree = "<group>"; };
608F974B2B752C4900DBE7D7 /* ValidateCheckoutEnvelope.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValidateCheckoutEnvelope.swift; sourceTree = "<group>"; };
6093098C2A6054CB004297AF /* GraphAPI.TriggerThirdPartyEventInput+TriggerThirdPartyEventInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "GraphAPI.TriggerThirdPartyEventInput+TriggerThirdPartyEventInput.swift"; sourceTree = "<group>"; };
6093098E2A6054D8004297AF /* GraphAPI.TriggerThirdPartyEventInput+TriggerThirdPartyEventInputTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "GraphAPI.TriggerThirdPartyEventInput+TriggerThirdPartyEventInputTests.swift"; sourceTree = "<group>"; };
609309902A60555F004297AF /* TriggerThirdPartyEventInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TriggerThirdPartyEventInput.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -5650,6 +5654,7 @@
0655C7272732FDA30087281F /* FetchRootCategories.graphql */,
0655C7292732FDE00087281F /* FetchCategory.graphql */,
E1A1491D2ACDD76700F49709 /* FetchBackerProjectsQuery.graphql */,
608F97492B7522EF00DBE7D7 /* ValidateCheckout.graphql */,
E1A149252ACE060E00F49709 /* templates */,
);
path = queries;
Expand Down Expand Up @@ -6725,6 +6730,7 @@
D6ED1B38216D50BE007F7547 /* UserEmailFields.swift */,
7798B5622174F494008BC50D /* UserEnvelope.swift */,
D01588241EEB2ED7006E7684 /* UserTests.swift */,
608F974B2B752C4900DBE7D7 /* ValidateCheckoutEnvelope.swift */,
D01588251EEB2ED7006E7684 /* VoidEnvelope.swift */,
8ABD5B3B24CFB026002E585C /* graphql */,
D01587971EEB2ED6006E7684 /* lenses */,
Expand Down Expand Up @@ -7356,6 +7362,7 @@
6008632E29B8F66F00B87B39 /* FetchUserEmail.graphql in Resources */,
399DAD8A2ACD163400238BA1 /* UnwatchProject.graphql in Resources */,
06DAAE5B26AA3CD800194E58 /* BackingFragment.graphql in Resources */,
608F974A2B7522EF00DBE7D7 /* ValidateCheckout.graphql in Resources */,
E1A1491E2ACDD76800F49709 /* FetchBackerProjectsQuery.graphql in Resources */,
6008632C29B8F64800B87B39 /* UserEmailFragment.graphql in Resources */,
47C0BCD826C42135003658AC /* CreatePaymentSource.graphql in Resources */,
Expand Down Expand Up @@ -8656,6 +8663,7 @@
4778EE2126A200BE0059EA69 /* UserEnvelope+GraphUserEnvelope.swift in Sources */,
8ADCCCAE264C98A50079D308 /* Comment.swift in Sources */,
609309912A60555F004297AF /* TriggerThirdPartyEventInput.swift in Sources */,
608F974C2B752C4900DBE7D7 /* ValidateCheckoutEnvelope.swift in Sources */,
D0158A2E1EEB30A2006E7684 /* User.AvatarTemplates.swift in Sources */,
D01588771EEB2ED7006E7684 /* FriendStatsEnvelope.swift in Sources */,
D015891D1EEB2ED7006E7684 /* ShippingRule.swift in Sources */,
Expand Down
157 changes: 157 additions & 0 deletions KsApi/GraphAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11004,6 +11004,163 @@ public enum GraphAPI {
}
}

public final class ValidateCheckoutQuery: GraphQLQuery {
/// The raw GraphQL definition of this operation.
public let operationDefinition: String =
"""
query ValidateCheckout($checkoutId: ID!, $paymentSourceId: String, $paymentIntentClientSecret: String!) {
checkout(id: $checkoutId) {
__typename
isValidForOnSessionCheckout(
paymentSourceId: $paymentSourceId
paymentIntentClientSecret: $paymentIntentClientSecret
) {
__typename
valid
messages
}
}
}
"""

public let operationName: String = "ValidateCheckout"

public var checkoutId: GraphQLID
public var paymentSourceId: String?
public var paymentIntentClientSecret: String

public init(checkoutId: GraphQLID, paymentSourceId: String? = nil, paymentIntentClientSecret: String) {
self.checkoutId = checkoutId
self.paymentSourceId = paymentSourceId
self.paymentIntentClientSecret = paymentIntentClientSecret
}

public var variables: GraphQLMap? {
return ["checkoutId": checkoutId, "paymentSourceId": paymentSourceId, "paymentIntentClientSecret": paymentIntentClientSecret]
}

public struct Data: GraphQLSelectionSet {
public static let possibleTypes: [String] = ["Query"]

public static var selections: [GraphQLSelection] {
return [
GraphQLField("checkout", arguments: ["id": GraphQLVariable("checkoutId")], type: .object(Checkout.selections)),
]
}

public private(set) var resultMap: ResultMap

public init(unsafeResultMap: ResultMap) {
self.resultMap = unsafeResultMap
}

public init(checkout: Checkout? = nil) {
self.init(unsafeResultMap: ["__typename": "Query", "checkout": checkout.flatMap { (value: Checkout) -> ResultMap in value.resultMap }])
}

/// Fetches a checkout given its id.
public var checkout: Checkout? {
get {
return (resultMap["checkout"] as? ResultMap).flatMap { Checkout(unsafeResultMap: $0) }
}
set {
resultMap.updateValue(newValue?.resultMap, forKey: "checkout")
}
}

public struct Checkout: GraphQLSelectionSet {
public static let possibleTypes: [String] = ["Checkout"]

public static var selections: [GraphQLSelection] {
return [
GraphQLField("__typename", type: .nonNull(.scalar(String.self))),
GraphQLField("isValidForOnSessionCheckout", arguments: ["paymentSourceId": GraphQLVariable("paymentSourceId"), "paymentIntentClientSecret": GraphQLVariable("paymentIntentClientSecret")], type: .nonNull(.object(IsValidForOnSessionCheckout.selections))),
]
}

public private(set) var resultMap: ResultMap

public init(unsafeResultMap: ResultMap) {
self.resultMap = unsafeResultMap
}

public init(isValidForOnSessionCheckout: IsValidForOnSessionCheckout) {
self.init(unsafeResultMap: ["__typename": "Checkout", "isValidForOnSessionCheckout": isValidForOnSessionCheckout.resultMap])
}

public var __typename: String {
get {
return resultMap["__typename"]! as! String
}
set {
resultMap.updateValue(newValue, forKey: "__typename")
}
}

/// Checks whether the checkout is valid prior to charging the user's card.
public var isValidForOnSessionCheckout: IsValidForOnSessionCheckout {
get {
return IsValidForOnSessionCheckout(unsafeResultMap: resultMap["isValidForOnSessionCheckout"]! as! ResultMap)
}
set {
resultMap.updateValue(newValue.resultMap, forKey: "isValidForOnSessionCheckout")
}
}

public struct IsValidForOnSessionCheckout: GraphQLSelectionSet {
public static let possibleTypes: [String] = ["Validation"]

public static var selections: [GraphQLSelection] {
return [
GraphQLField("__typename", type: .nonNull(.scalar(String.self))),
GraphQLField("valid", type: .nonNull(.scalar(Bool.self))),
GraphQLField("messages", type: .nonNull(.list(.nonNull(.scalar(String.self))))),
]
}

public private(set) var resultMap: ResultMap

public init(unsafeResultMap: ResultMap) {
self.resultMap = unsafeResultMap
}

public init(valid: Bool, messages: [String]) {
self.init(unsafeResultMap: ["__typename": "Validation", "valid": valid, "messages": messages])
}

public var __typename: String {
get {
return resultMap["__typename"]! as! String
}
set {
resultMap.updateValue(newValue, forKey: "__typename")
}
}

/// Whether a value is valid.
public var valid: Bool {
get {
return resultMap["valid"]! as! Bool
}
set {
resultMap.updateValue(newValue, forKey: "valid")
}
}

/// Error messages associated with the value
public var messages: [String] {
get {
return resultMap["messages"]! as! [String]
}
set {
resultMap.updateValue(newValue, forKey: "messages")
}
}
}
}
}
}

public struct BackingFragment: GraphQLFragment {
/// The raw GraphQL definition of this fragment.
public static let fragmentDefinition: String =
Expand Down
13 changes: 13 additions & 0 deletions KsApi/MockService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,8 @@
ErrorEnvelope
>?

fileprivate let validateCheckoutResult: Result<ValidateCheckoutEnvelope, ErrorEnvelope>?

fileprivate let verifyEmailResult: Result<EmailVerificationResponseEnvelope, ErrorEnvelope>?

fileprivate let watchProjectMutationResult: Result<
Expand Down Expand Up @@ -316,6 +318,7 @@
updateProjectNotificationError: ErrorEnvelope? = nil,
updateUserSelfError: ErrorEnvelope? = nil,
unwatchProjectMutationResult: Result<WatchProjectResponseEnvelope, ErrorEnvelope>? = nil,
validateCheckoutResult: Result<ValidateCheckoutEnvelope, ErrorEnvelope>? = nil,
verifyEmailResult: Result<EmailVerificationResponseEnvelope, ErrorEnvelope>? = nil,
watchProjectMutationResult: Result<WatchProjectResponseEnvelope, ErrorEnvelope>? = nil
) {
Expand Down Expand Up @@ -516,6 +519,8 @@

self.unwatchProjectMutationResult = unwatchProjectMutationResult

self.validateCheckoutResult = validateCheckoutResult

self.verifyEmailResult = verifyEmailResult

self.watchProjectMutationResult = watchProjectMutationResult
Expand Down Expand Up @@ -1649,6 +1654,14 @@
.performWithResult(mutation: mutationUnwatchProject, result: self.unwatchProjectMutationResult)
}

internal func validateCheckout(
checkoutId _: String,
paymentSourceId _: String?,
paymentIntentClientSecret _: String
) -> SignalProducer<ValidateCheckoutEnvelope, ErrorEnvelope> {
return producer(for: self.validateCheckoutResult)
}

internal func verifyEmail(withToken _: String)
-> SignalProducer<EmailVerificationResponseEnvelope, ErrorEnvelope> {
return producer(for: self.verifyEmailResult)
Expand Down
20 changes: 20 additions & 0 deletions KsApi/Service.swift
Original file line number Diff line number Diff line change
Expand Up @@ -805,4 +805,24 @@ public struct Service: ServiceType {
SignalProducer(value: EmptyResponseEnvelope())
}
}

/**
Post Campaign Pledge Validation.
- parameter checkoutId: The Checkout Id..
- parameter paymentSourceId: The id of the payment source.
- parameter paymentIntentClientSecret: The client secret returned from our CreatePaymentIntent Mutation.
*/
public func validateCheckout(
checkoutId: String,
paymentSourceId: String?,
paymentIntentClientSecret: String
) -> SignalProducer<ValidateCheckoutEnvelope, ErrorEnvelope> {
return GraphQL.shared.client
.fetch(query: GraphAPI.ValidateCheckoutQuery(
checkoutId: checkoutId,
paymentSourceId: paymentSourceId,
paymentIntentClientSecret: paymentIntentClientSecret
))
.flatMap(ValidateCheckoutEnvelope.envelopeProducer(from:))
}
}
7 changes: 7 additions & 0 deletions KsApi/ServiceType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,13 @@ public protocol ServiceType {
func unwatchProject(input: WatchProjectInput) ->
SignalProducer<WatchProjectResponseEnvelope, ErrorEnvelope>

/// Validates a Post Campaign Pledge
func validateCheckout(
checkoutId: String,
paymentSourceId: String?,
paymentIntentClientSecret: String
) -> SignalProducer<ValidateCheckoutEnvelope, ErrorEnvelope>

/// Verifies an email address with a given access token.
func verifyEmail(withToken token: String)
-> SignalProducer<EmailVerificationResponseEnvelope, ErrorEnvelope>
Expand Down
31 changes: 31 additions & 0 deletions KsApi/models/ValidateCheckoutEnvelope.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import Foundation
import ReactiveSwift

public struct ValidateCheckoutEnvelope: Decodable {
public let valid: Bool
public let messages: [String]
}

// MARK: - GraphQL Adapters

extension ValidateCheckoutEnvelope {
static func envelopeProducer(from data: GraphAPI.ValidateCheckoutQuery.Data)
-> SignalProducer<ValidateCheckoutEnvelope, ErrorEnvelope> {
guard let envelope = ValidateCheckoutEnvelope.validateCheckoutEnvelope(from: data) else {
return SignalProducer(error: .couldNotParseJSON)
}
return SignalProducer(value: envelope)
}

/**
Returns a minimal `ValidateCheckoutEnvelope` from a `GraphAPI.ValidateCheckoutQuery.Data`
*/
static func validateCheckoutEnvelope(from data: GraphAPI.ValidateCheckoutQuery
.Data) -> ValidateCheckoutEnvelope? {
guard let valid = data.checkout?.isValidForOnSessionCheckout.valid,
let messages = data.checkout?.isValidForOnSessionCheckout.messages
else { return nil }

return ValidateCheckoutEnvelope(valid: valid, messages: messages)
}
}
8 changes: 8 additions & 0 deletions KsApi/queries/ValidateCheckout.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
query ValidateCheckout($checkoutId: ID!, $paymentSourceId: String, $paymentIntentClientSecret: String!) {
checkout(id: $checkoutId) {
isValidForOnSessionCheckout(paymentSourceId: $paymentSourceId, paymentIntentClientSecret: $paymentIntentClientSecret) {
valid
messages
}
}
}

0 comments on commit 0d5974b

Please sign in to comment.