From d82521890a51b86c183cdf0111a270ab7402089d Mon Sep 17 00:00:00 2001 From: Ash Furrow Date: Mon, 29 Oct 2018 16:25:03 -0400 Subject: [PATCH 1/3] Revert "Merge pull request #687 from artsy/cardflight-update" This reverts commit 24c721af3a9991c7c1ebd5dcaef80f470cf5ddcc, reversing changes made to e98923f54a3fee3642051b9f48556c5e912591e0. --- Kiosk.xcodeproj/project.pbxproj | 3 - .../AdminCardTestingViewController.swift | 10 +- Kiosk/App/CardHandler.swift | 198 ++++++------------ Kiosk/App/GlobalFunctions.swift | 2 +- .../SwipeCreditCardViewController.swift | 30 +-- Kiosk/Storyboards/Fulfillment.storyboard | 154 +++++++------- Kiosk/Supporting Files/Info.plist | 25 +-- Kiosk/Supporting Files/PodsBridgingHeader.h | 2 + KioskTests/CardHandlerTests.swift | 108 ++++------ Podfile | 2 +- Podfile.lock | 8 +- 11 files changed, 220 insertions(+), 322 deletions(-) diff --git a/Kiosk.xcodeproj/project.pbxproj b/Kiosk.xcodeproj/project.pbxproj index 02c48fb2..be5d3d94 100644 --- a/Kiosk.xcodeproj/project.pbxproj +++ b/Kiosk.xcodeproj/project.pbxproj @@ -1151,7 +1151,6 @@ "${BUILT_PRODUCTS_DIR}/Artsy+UIFonts/Artsy_UIFonts.framework", "${BUILT_PRODUCTS_DIR}/Artsy+UILabels/Artsy_UILabels.framework", "${BUILT_PRODUCTS_DIR}/Artsy-UIButtons/Artsy_UIButtons.framework", - "${PODS_ROOT}/CardFlight-v4/CardFlight.framework", "${BUILT_PRODUCTS_DIR}/DZNWebViewController/DZNWebViewController.framework", "${BUILT_PRODUCTS_DIR}/ECPhoneNumberFormatter/ECPhoneNumberFormatter.framework", "${BUILT_PRODUCTS_DIR}/FLKAutoLayout/FLKAutoLayout.framework", @@ -1187,7 +1186,6 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Artsy_UIFonts.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Artsy_UILabels.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Artsy_UIButtons.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/CardFlight.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DZNWebViewController.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ECPhoneNumberFormatter.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FLKAutoLayout.framework", @@ -1553,7 +1551,6 @@ "$(SRCROOT)/Pods/CardFlight/**", ); INFOPLIST_FILE = "Kiosk/Supporting Files/Info.plist"; - OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" -DDEBUG"; PRODUCT_BUNDLE_IDENTIFIER = net.artsy.kiosk.beta; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Kiosk/Supporting Files/BridgingHeader.h"; diff --git a/Kiosk/Admin/AdminCardTestingViewController.swift b/Kiosk/Admin/AdminCardTestingViewController.swift index d4d50986..4a2b169b 100644 --- a/Kiosk/Admin/AdminCardTestingViewController.swift +++ b/Kiosk/Admin/AdminCardTestingViewController.swift @@ -38,11 +38,14 @@ class AdminCardTestingViewController: UIViewController { return } - let cardDetails = "Card: \(card.cardInfo.cardholderName ?? "") - \(card.cardInfo.lastFour ?? "") \n \(card.token)" + let cardDetails = "Card: \(card.name ?? "") - \(card.last4 ?? "") \n \(card.cardToken ?? "")" self.log(cardDetails) } } .disposed(by: rx.disposeBag) + + + cardHandler.startSearching() } override func viewWillDisappear(_ animated: Bool) { @@ -50,11 +53,6 @@ class AdminCardTestingViewController: UIViewController { cardHandler.end() } - override func viewDidAppear(_ animated: Bool) { - super.viewDidAppear(animated) - cardHandler.startSearching() - } - func log(_ string: String) { self.logTextView.text = "\(self.logTextView.text ?? "")\n\(string)" diff --git a/Kiosk/App/CardHandler.swift b/Kiosk/App/CardHandler.swift index cdf814b7..6dba935c 100644 --- a/Kiosk/App/CardHandler.swift +++ b/Kiosk/App/CardHandler.swift @@ -1,181 +1,107 @@ import UIKit import RxSwift -import CardFlight -class CardHandler: NSObject, CFTTransactionDelegate { +class CardHandler: NSObject, CFTReaderDelegate { - private let _cardStatus = PublishSubject() - private let _userMessages = PublishSubject() - private var cardReader: CFTCardReaderInfo? - - var transaction: CFTTransaction? + fileprivate let _cardStatus = PublishSubject() var cardStatus: Observable { return _cardStatus.asObservable() } - var userMessages: Observable { - // User messages are things like "Swipe card", "processing", or "Swipe card again". Due to a problem with the - // CardFlight SDK, the user is prompted to accept processing for card tokenization, which is provides a - // unfriendly user experience (prompting to accept a transaction that we're not actually placing). So we - // auto-accept these requests and filter out confirmation messages, which don't apply to tokenization flows, - // until this issue is fixed: https://github.com/CardFlight/cardflight-v4-ios/issues/4 - return _userMessages - .asObservable() - .filter { message -> Bool in - !message.hasSuffix("?") - } - } - - var cardFlightCredentials: CFTCredentials { - let credentials = CFTCredentials() - credentials.setup(apiKey: self.APIKey, accountToken: self.APIToken, completion: nil) - return credentials - } - - var card: (cardInfo: CFTCardInfo, token: String)? - - + var card: CFTCard? + let APIKey: String let APIToken: String + var reader: CFTReader! + lazy var sessionManager = CFTSessionManager.sharedInstance()! + init(apiKey: String, accountToken: String){ APIKey = apiKey APIToken = accountToken super.init() - self.transaction = CFTTransaction(delegate: self) - } - - deinit { - self.end() + sessionManager.setApiToken(APIKey, accountToken: APIToken, completed: nil) } func startSearching() { - _cardStatus.onNext("Starting search...") - let tokenizationParameters = CFTTokenizationParameters(customerId: nil, credentials: self.cardFlightCredentials) - self.transaction?.beginTokenizing(tokenizationParameters: tokenizationParameters) - } + sessionManager.setLogging(true) - func end() { - transaction?.select(processOption: CFTProcessOption.abort) - transaction = nil + reader = CFTReader(reader: CFTReaderType.UNKNOWN) + reader.delegate = self + reader.swipeHasTimeout(false) + _cardStatus.onNext("Started searching") } - func transaction(_ transaction: CFTTransaction, didUpdate state: CFTTransactionState, error: Error?) { - switch state { - case .completed: - _cardStatus.onNext("Transaction completed") - case .processing: - _cardStatus.onNext("Transaction processing") - case .deferred: - _cardStatus.onNext("Transaction deferred") - case .pendingCardInput: - _cardStatus.onNext("Pending card input") - transaction.select(cardReaderInfo: cardReader, cardReaderModel: cardReader?.cardReaderModel ?? .unknown) - case .pendingTransactionParameters: - _cardStatus.onNext("Pending transaction parameters") - case .unknown: - _cardStatus.onNext("Unknown transactionstate") - case .pendingProcessOption: - break - } + func end() { + reader.cancelTransaction() + reader = nil } - func transaction(_ transaction: CFTTransaction, didComplete historicalTransaction: CFTHistoricalTransaction) { - if let cardInfo = historicalTransaction.cardInfo, let token = historicalTransaction.cardToken { - self.card = (cardInfo: cardInfo, token: token) + func readerCardResponse(_ card: CFTCard?, withError error: Error?) { + if let card = card { + self.card = card; _cardStatus.onNext("Got Card") - _cardStatus.onCompleted() - } else { - _cardStatus.onNext("Card Flight Error – could not retrieve card data."); - if let error = historicalTransaction.error { - _cardStatus.onNext("response Error \(error)"); - logger.log("CardReader got a response it cannot handle") - } - startSearching() + + card.tokenizeCard(success: { [weak self] in + self?._cardStatus.onCompleted() + logger.log("Card was tokenized") + + }, failure: { [weak self] (error) in + self?._cardStatus.onNext("Card Flight Error: \(String(describing: error))"); + logger.log("Card was not tokenizable") + }) + + } else if let error = error { + self._cardStatus.onNext("response Error \(error)"); + logger.log("CardReader got a response it cannot handle") + + + reader.beginSwipe(); } } - func transaction(_ transaction: CFTTransaction, didReceive cardReaderEvent: CFTCardReaderEvent, cardReaderInfo: CFTCardReaderInfo?) { - _cardStatus.onNext(cardReaderEvent.statusMessage) + func transactionResult(_ charge: CFTCharge!, withError error: Error!) { + logger.log("Unexcepted call to transactionResult callback: \(charge)\n\(error)") } - func transaction(_ transaction: CFTTransaction, didUpdate cardReaderArray: [CFTCardReaderInfo]) { - self.cardReader = cardReaderArray.first - _cardStatus.onNext("Received new card reader availability, number of readers: \(cardReaderArray.count)") + // handle other delegate call backs with the status messages + + func readerIsAttached() { + _cardStatus.onNext("Reader is attatched"); } - func transaction(_ transaction: CFTTransaction, didRequestProcessOption cardInfo: CFTCardInfo) { - logger.log("Received request for processing option, will process transaction.") - _cardStatus.onNext("Request for process option, automatically processing...") - // We auto-accept the process option on the user's behalf because the prompt doesn't make sense in a - // tokenization flow. See comments in `userMessages` property above. - transaction.select(processOption: .process) + func readerIsConnecting() { + _cardStatus.onNext("Reader is connecting"); } - func transaction(_ transaction: CFTTransaction, didRequestDisplay message: CFTMessage) { - let message = message.primary ?? message.secondary ?? "" - _userMessages.onNext(message) - logger.log("Received request to display message: \(message)") - _cardStatus.onNext("Received message for user: \(message)") + func readerIsDisconnected() { + _cardStatus.onNext("Reader is disconnected"); + logger.log("Card Reader Disconnected") } -} -typealias UnhandledDelegateCallbacks = CardHandler -/// We don't expect any of these functions to be called, but they are required for the delegate protocol. -extension UnhandledDelegateCallbacks { - func transaction(_ transaction: CFTTransaction, didDefer transactionData: Data) { - logger.log("Transaction has been deferred.") - _cardStatus.onNext("Transaction deferred") + func readerSwipeDidCancel() { + _cardStatus.onNext("Reader did cancel"); + logger.log("Card Reader was Cancelled") } - public func transaction(_ transaction: CFTTransaction, didRequest cvm: CFTCVM) { - if cvm == CFTCVM.signature { - logger.log("Transaction requested signature from user, which should not occur for tokenization.") - _cardStatus.onNext("Ignoring user signature request from CardFlight") - } + func readerGenericResponse(_ cardData: String!) { + _cardStatus.onNext("Reader received non-card data: \(cardData ?? "") "); + reader.beginSwipe() } -} -extension CFTCardReaderEvent { - var statusMessage: String { - switch self { - case .unknown: - return "Unknown card event" - case .disconnected: - return "Reader is disconnected" - case .connected: - return "Reader is connected" - case .connectionErrored: - return "Connection error occurred" - case .cardSwiped: - return "Card swiped" - case .cardSwipeErrored: - return "Card swipe error" - case .cardInserted: - return "Card inserted" - case .cardInsertErrored: - return "Card insertion error" - case .cardRemoved: - return "Card removed" - case .cardTapped: - return "Card tapped" - case .cardTapErrored: - return "Card tap error" - case .updateStarted: - return "Update started" - case .updateCompleted: - return "Updated completed" - case .audioRecordingPermissionNotGranted: - return "iOS audio permissions no granted" - case .fatalError: - return "Fatal error" - case .connecting: - return "Connecting" - case .batteryStatusUpdated: - return "Battery status updated" + func readerIsConnected(_ isConnected: Bool, withError error: Error!) { + if isConnected { + _cardStatus.onNext("Reader is connected") + reader.beginSwipe() + } else { + if (error != nil) { + _cardStatus.onNext("Reader is disconnected: \(error.localizedDescription)"); + } else { + _cardStatus.onNext("Reader is disconnected"); + } } } } diff --git a/Kiosk/App/GlobalFunctions.swift b/Kiosk/App/GlobalFunctions.swift index 298e237a..ef76f695 100644 --- a/Kiosk/App/GlobalFunctions.swift +++ b/Kiosk/App/GlobalFunctions.swift @@ -36,7 +36,7 @@ func responseIsOK(_ response: Response) -> Bool { func detectDevelopmentEnvironment() -> Bool { var developmentEnvironment = false - #if DEBUG || (arch(i386) || arch(x86_64)) + #if DEBUG || (arch(i386) || arch(x86_64)) && os(iOS) developmentEnvironment = true #endif return developmentEnvironment diff --git a/Kiosk/Bid Fulfillment/SwipeCreditCardViewController.swift b/Kiosk/Bid Fulfillment/SwipeCreditCardViewController.swift index cdf7f03c..edda3582 100644 --- a/Kiosk/Bid Fulfillment/SwipeCreditCardViewController.swift +++ b/Kiosk/Bid Fulfillment/SwipeCreditCardViewController.swift @@ -9,10 +9,11 @@ class SwipeCreditCardViewController: UIViewController, RegistrationSubController @IBOutlet var cardStatusLabel: ARSerifLabel! let finished = PublishSubject() - @IBOutlet weak var titleLabel: ARSerifLabel! @IBOutlet weak var spinner: Spinner! + @IBOutlet weak var processingLabel: UILabel! @IBOutlet weak var illustrationImageView: UIImageView! + @IBOutlet weak var titleLabel: ARSerifLabel! class func instantiateFromStoryboard(_ storyboard: UIStoryboard) -> SwipeCreditCardViewController { return storyboard.viewController(withID: .RegisterCreditCard) as! SwipeCreditCardViewController @@ -43,20 +44,6 @@ class SwipeCreditCardViewController: UIViewController, RegistrationSubController super.viewDidLoad() self.setInProgress(false) - let pleaseWaitMessage = "Please wait..." - - cardHandler.userMessages - .startWith(pleaseWaitMessage) - .map { message in - if message.isEmpty { - return pleaseWaitMessage - } else { - return message - } - } - .bind(to: titleLabel.rx.text) - .disposed(by: rx.disposeBag) - cardHandler.cardStatus .takeUntil(self.viewWillDisappear) .subscribe(onNext: { message in @@ -64,6 +51,10 @@ class SwipeCreditCardViewController: UIViewController, RegistrationSubController if message == "Got Card" { self.setInProgress(true) } + + if message.hasPrefix("Card Flight Error") { + self.processingLabel.text = "ERROR PROCESSING CARD - SEE ADMIN" + } }, onError: { error in self.cardStatusLabel.text = "Card Status: Errored" @@ -75,13 +66,13 @@ class SwipeCreditCardViewController: UIViewController, RegistrationSubController self.cardStatusLabel.text = "Card Status: completed" if let card = self.cardHandler.card { - self.cardName.value = card.cardInfo.cardholderName ?? "" - self.cardLastDigits.value = card.cardInfo.lastFour ?? "" + self.cardName.value = card.name + self.cardLastDigits.value = card.last4 - self.cardToken.value = card.token + self.cardToken.value = card.cardToken if let newUser = self.navigationController?.fulfillmentNav().bidDetails.newUser { - newUser.name.value = (newUser.name.value.isNilOrEmpty) ? card.cardInfo.cardholderName : newUser.name.value + newUser.name.value = (newUser.name.value.isNilOrEmpty) ? card.name : newUser.name.value } } @@ -125,6 +116,7 @@ class SwipeCreditCardViewController: UIViewController, RegistrationSubController func setInProgress(_ show: Bool) { illustrationImageView.alpha = show ? 0.1 : 1 + processingLabel.isHidden = !show spinner.isHidden = !show } diff --git a/Kiosk/Storyboards/Fulfillment.storyboard b/Kiosk/Storyboards/Fulfillment.storyboard index 688740ea..09862832 100644 --- a/Kiosk/Storyboards/Fulfillment.storyboard +++ b/Kiosk/Storyboards/Fulfillment.storyboard @@ -1,11 +1,11 @@ - + - + @@ -90,6 +90,7 @@ + @@ -113,7 +114,7 @@ - + @@ -121,7 +122,7 @@ - + @@ -192,7 +193,7 @@ - + @@ -211,7 +212,7 @@ - + @@ -219,7 +220,7 @@ - + @@ -271,7 +272,7 @@ + @@ -446,6 +453,7 @@ + @@ -469,7 +477,7 @@ - + @@ -487,7 +495,7 @@ - + - + - + @@ -653,7 +661,7 @@ - + - + @@ -727,7 +735,7 @@ - + @@ -790,7 +798,7 @@ - + @@ -799,7 +807,7 @@ - + @@ -839,7 +847,7 @@ - + @@ -848,7 +856,7 @@ - + - + @@ -906,7 +914,7 @@