Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Increase flexibility of ForageElement hierarchy #248

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: 1 addition & 1 deletion forage-android/consumer-rules.pro
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# This ensures that the ProxyRequestObject property names (like card_number_token) are preserved
# and are not obfuscated when consumed by clients who use ProGuard.
-keepclassmembers class com.joinforage.forage.android.vault.ProxyRequestObject {
-keepclassmembers class com.joinforage.forage.android.ecom.services.vault.bt.ProxyRequestObject {
*;
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package com.joinforage.forage.android
package com.joinforage.forage.android.core

import com.joinforage.forage.android.network.model.ForageApiResponse
import com.joinforage.forage.android.ui.ForagePANEditText
import com.joinforage.forage.android.ui.ForagePINEditText
import com.joinforage.forage.android.core.services.forageapi.network.ForageApiResponse
import com.joinforage.forage.android.core.ui.element.ForagePanElement
import com.joinforage.forage.android.core.ui.element.ForagePinElement

/**
* An [Exception](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-exception/) thrown if a
Expand Down Expand Up @@ -98,7 +98,7 @@ internal interface ForageSDKInterface {
* to create multiple payments, set to true by default.
*/
data class TokenizeEBTCardParams(
val foragePanEditText: ForagePANEditText,
val foragePanEditText: ForagePanElement,
val customerId: String? = null,
devinmorgan marked this conversation as resolved.
Show resolved Hide resolved
val reusable: Boolean = true
)
Expand All @@ -120,7 +120,7 @@ data class TokenizeEBTCardParams(
* endpoint.
*/
data class CheckBalanceParams(
val foragePinEditText: ForagePINEditText,
val foragePinEditText: ForagePinElement,
val paymentMethodRef: String
)

Expand All @@ -138,7 +138,7 @@ data class CheckBalanceParams(
* [Create a `Payment`](https://docs.joinforage.app/reference/create-a-payment) endpoint.
*/
data class CapturePaymentParams(
val foragePinEditText: ForagePINEditText,
val foragePinEditText: ForagePinElement,
val paymentRef: String
)

Expand All @@ -163,6 +163,6 @@ data class CapturePaymentParams(
* [Create a `Payment`](https://docs.joinforage.app/reference/create-a-payment) endpoint.
*/
data class DeferPaymentCaptureParams(
val foragePinEditText: ForagePINEditText,
val foragePinEditText: ForagePinElement,
val paymentRef: String
)

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.joinforage.forage.android.core
package com.joinforage.forage.android.core.services

import com.joinforage.forage.android.BuildConfig
import com.joinforage.forage.android.ui.ForageConfig
import com.joinforage.forage.android.core.ui.element.ForageConfig

internal enum class EnvOption(val value: String) {
LOCAL("local"),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package com.joinforage.forage.android.core.services

import com.joinforage.forage.android.core.services.forageapi.network.ForageError
import okhttp3.HttpUrl
import org.json.JSONObject
import kotlin.random.Random

/**
* We generate a random jitter amount to add to our retry delay when polling for the status of
* Payments and Payment Methods so that we can avoid a thundering herd scenario in which there are
* several requests retrying at the same exact time.
*
* Returns a random integer between -25 and 25
*/
internal fun getJitterAmount(random: Random = Random.Default): Int {
return random.nextInt(-25, 26)
}

internal fun HttpUrl.Builder.addTrailingSlash(): HttpUrl.Builder {
return this.addPathSegment("")
}

internal object ForageConstants {

object Headers {
const val X_KEY = "X-KEY"
const val MERCHANT_ACCOUNT = "Merchant-Account"
const val IDEMPOTENCY_KEY = "IDEMPOTENCY-KEY"
const val TRACE_ID = "x-datadog-trace-id"
const val AUTHORIZATION = "Authorization"
const val BEARER = "Bearer"
const val API_VERSION = "API-VERSION"
const val BT_PROXY_KEY = "BT-PROXY-KEY"
const val CONTENT_TYPE = "Content-Type"
}

object RequestBody {
const val CARD_NUMBER_TOKEN = "card_number_token"

// POS-only
const val REASON = "reason"
const val METADATA = "metadata"
const val AMOUNT = "amount"
const val POS_TERMINAL = "pos_terminal"
const val PROVIDER_TERMINAL_ID = "provider_terminal_id"
}

object PathSegment {
const val ISO_SERVER = "iso_server"
const val ENCRYPTION_ALIAS = "encryption_alias"
const val API = "api"
const val PAYMENT_METHODS = "payment_methods"
const val MESSAGE = "message"
const val PAYMENTS = "payments"
const val REFUNDS = "refunds"
}

object VGS {
const val PIN_FIELD_NAME = "pin"
}

object ErrorResponseObjects {
val INCOMPLETE_PIN_ERROR = listOf(
ForageError(
400,
"user_error",
"Invalid EBT Card PIN entered. Please enter your 4-digit PIN."
)
)
}
}

internal enum class VaultType(val value: String) {
VGS_VAULT_TYPE("vgs"),
BT_VAULT_TYPE("basis_theory"),
FORAGE_VAULT_TYPE("forage");

override fun toString(): String {
return value
}
}

// This extension splits the path by "/" and adds each segment individually to the path.
// This is to prevent the URL from getting corrupted through internal OKHttp URL encoding.
internal fun HttpUrl.Builder.addPathSegmentsSafe(path: String): HttpUrl.Builder {
path.split("/").forEach { segment ->
if (segment.isNotEmpty()) {
this.addPathSegment(segment)
}
}
return this
}

/**
* [JSONObject.optString] has trouble falling back to `null` and seems to fallback to `"null"` (string) instead
*/
internal fun JSONObject.getStringOrNull(fieldName: String): String? {
if (!has(fieldName) || isNull(fieldName)) {
return null
}
return optString(fieldName)
}

internal fun JSONObject.hasNonNull(fieldName: String): Boolean {
return has(fieldName) && !isNull(fieldName)
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package com.joinforage.forage.android.network
package com.joinforage.forage.android.core.services.forageapi.encryptkey

import com.joinforage.forage.android.addTrailingSlash
import com.joinforage.forage.android.core.telemetry.Log
import com.joinforage.forage.android.network.model.ForageApiResponse
import com.joinforage.forage.android.network.model.ForageError
import com.joinforage.forage.android.core.services.ForageConstants
import com.joinforage.forage.android.core.services.addTrailingSlash
import com.joinforage.forage.android.core.services.forageapi.network.ForageApiResponse
import com.joinforage.forage.android.core.services.forageapi.network.ForageError
import com.joinforage.forage.android.core.services.forageapi.network.NetworkService
import com.joinforage.forage.android.core.services.telemetry.Log
import okhttp3.HttpUrl
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import okhttp3.OkHttpClient
Expand All @@ -20,7 +22,15 @@ internal class EncryptionKeyService(
getEncryptionToCoroutine()
} catch (ex: IOException) {
logger.e("[HTTP] Failed while trying to GET Encryption Key", ex)
ForageApiResponse.Failure(listOf(ForageError(500, "unknown_server_error", ex.message.orEmpty())))
ForageApiResponse.Failure(
listOf(
ForageError(
500,
"unknown_server_error",
ex.message.orEmpty()
)
)
)
}

private suspend fun getEncryptionToCoroutine(): ForageApiResponse<String> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.joinforage.forage.android.model
package com.joinforage.forage.android.core.services.forageapi.encryptkey

import org.json.JSONObject

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
package com.joinforage.forage.android.network.model
package com.joinforage.forage.android.core.services.forageapi.network

import com.joinforage.forage.android.core.services.forageapi.payment.Payment
import com.joinforage.forage.android.core.services.forageapi.paymentmethod.Balance
import com.joinforage.forage.android.core.services.forageapi.paymentmethod.EbtBalance
import com.joinforage.forage.android.core.services.forageapi.paymentmethod.PaymentMethod
import com.joinforage.forage.android.core.services.forageapi.polling.ForageErrorDetails
import org.json.JSONException
import org.json.JSONObject

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
package com.joinforage.forage.android.network
package com.joinforage.forage.android.core.services.forageapi.network

import com.joinforage.forage.android.core.telemetry.Log
import com.joinforage.forage.android.network.model.ForageApiError
import com.joinforage.forage.android.network.model.ForageApiResponse
import com.joinforage.forage.android.network.model.ForageError
import com.joinforage.forage.android.network.model.UnknownErrorApiResponse
import com.joinforage.forage.android.core.services.telemetry.Log
import okhttp3.Call
import okhttp3.Callback
import okhttp3.OkHttpClient
Expand Down Expand Up @@ -32,13 +28,20 @@ internal abstract class NetworkService(
val body = response.body
if (body != null) {
try {
val parsedError = ForageApiError.ForageApiErrorMapper.from(body.string())
val parsedError =
ForageApiError.ForageApiErrorMapper.from(body.string())
val error = parsedError.errors[0]
logger.e("[HTTP] Received ${response.code} response from API ${parsedError.path} with message: ${error.message}")

continuation.resumeWith(
Result.success(
ForageApiResponse.Failure.fromError(ForageError(response.code, error.code, error.message))
ForageApiResponse.Failure.fromError(
ForageError(
response.code,
error.code,
error.message
)
)
)
)
} catch (e: Exception) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.joinforage.forage.android.network
package com.joinforage.forage.android.core.services.forageapi.network

import com.joinforage.forage.android.core.services.ForageConstants
import okhttp3.Interceptor
import okhttp3.OkHttpClient

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package com.joinforage.forage.android.network.model
package com.joinforage.forage.android.core.services.forageapi.payment

import com.joinforage.forage.android.getStringOrNull
import com.joinforage.forage.android.hasNonNull
import com.joinforage.forage.android.core.services.forageapi.paymentmethod.Balance
import com.joinforage.forage.android.core.services.forageapi.paymentmethod.EbtBalance
import com.joinforage.forage.android.core.services.getStringOrNull
import com.joinforage.forage.android.core.services.hasNonNull
import org.json.JSONArray
import org.json.JSONObject

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package com.joinforage.forage.android.network
package com.joinforage.forage.android.core.services.forageapi.payment

import com.joinforage.forage.android.addTrailingSlash
import com.joinforage.forage.android.core.telemetry.Log
import com.joinforage.forage.android.network.model.ForageApiResponse
import com.joinforage.forage.android.network.model.ForageError
import com.joinforage.forage.android.core.services.ForageConstants
import com.joinforage.forage.android.core.services.addTrailingSlash
import com.joinforage.forage.android.core.services.forageapi.network.ForageApiResponse
import com.joinforage.forage.android.core.services.forageapi.network.ForageError
import com.joinforage.forage.android.core.services.forageapi.network.NetworkService
import com.joinforage.forage.android.core.services.telemetry.Log
import okhttp3.HttpUrl
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import okhttp3.OkHttpClient
Expand All @@ -29,7 +31,15 @@ internal class PaymentService(
ex,
attributes = mapOf("payment_ref" to paymentRef)
)
ForageApiResponse.Failure(listOf(ForageError(500, "unknown_server_error", ex.message.orEmpty())))
ForageApiResponse.Failure(
listOf(
ForageError(
500,
"unknown_server_error",
ex.message.orEmpty()
)
)
)
}

private suspend fun getPaymentToCoroutine(paymentRef: String): ForageApiResponse<String> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.joinforage.forage.android.network.model
package com.joinforage.forage.android.core.services.forageapi.paymentmethod

import org.json.JSONObject

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.joinforage.forage.android.network.model
package com.joinforage.forage.android.core.services.forageapi.paymentmethod

import com.joinforage.forage.android.getStringOrNull
import com.joinforage.forage.android.model.USState
import com.joinforage.forage.android.core.services.getStringOrNull
import com.joinforage.forage.android.core.ui.element.state.USState
import org.json.JSONObject

/**
Expand Down
Loading
Loading