Skip to content

Commit

Permalink
Add MerchantRepository for holding BraintreeClient properties (#1202)
Browse files Browse the repository at this point in the history
* Move properties from BraintreeClient to MerchantRepository

* Add kdocs for MerchantRepository
  • Loading branch information
tdchow authored Nov 5, 2024
1 parent 4d0211a commit ed09136
Show file tree
Hide file tree
Showing 21 changed files with 1,241 additions and 672 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,35 +17,18 @@ import org.json.JSONObject
@Suppress("LargeClass", "LongParameterList", "TooManyFunctions")
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
class BraintreeClient internal constructor(

/**
* @suppress
*/
val applicationContext: Context,

/**
* @suppress
*/
val integrationType: IntegrationType,

/**
* @suppress
*/
val authorization: Authorization,

private val returnUrlScheme: String,

/**
* @suppress
*/
val appLinkReturnUri: Uri?,

applicationContext: Context,
integrationType: IntegrationType,
authorization: Authorization,
returnUrlScheme: String,
appLinkReturnUri: Uri?,
private val analyticsClient: AnalyticsClient = AnalyticsClient(applicationContext),
private val httpClient: BraintreeHttpClient = BraintreeHttpClient(),
private val graphQLClient: BraintreeGraphQLClient = BraintreeGraphQLClient(),
private val configurationLoader: ConfigurationLoader = ConfigurationLoader(applicationContext, httpClient),
private val manifestValidator: ManifestValidator = ManifestValidator(),
private val time: Time = Time(),
private val merchantRepository: MerchantRepository = MerchantRepository.instance
) {

private val crashReporter: CrashReporter
Expand Down Expand Up @@ -80,6 +63,16 @@ class BraintreeClient internal constructor(
// statistics access via the sdk console
crashReporter = CrashReporter(this)
crashReporter.start()

merchantRepository.let {
it.applicationContext = applicationContext
it.integrationType = integrationType
it.authorization = authorization
it.returnUrlScheme = returnUrlScheme
if (appLinkReturnUri != null) {
it.appLinkReturnUri = appLinkReturnUri
}
}
}

/**
Expand All @@ -88,11 +81,11 @@ class BraintreeClient internal constructor(
* @param callback [ConfigurationCallback]
*/
fun getConfiguration(callback: ConfigurationCallback) {
if (authorization is InvalidAuthorization) {
if (merchantRepository.authorization is InvalidAuthorization) {
callback.onResult(null, createAuthError())
return
}
configurationLoader.loadConfiguration(authorization) { configuration, configError, timing ->
configurationLoader.loadConfiguration(merchantRepository.authorization) { configuration, configError, timing ->
if (configuration != null) {
callback.onResult(configuration, null)
} else {
Expand Down Expand Up @@ -123,7 +116,7 @@ class BraintreeClient internal constructor(
experiment = params.experiment,
paymentMethodsDisplayed = params.paymentMethodsDisplayed
)
sendAnalyticsEvent(event, configuration, authorization)
sendAnalyticsEvent(event, configuration, merchantRepository.authorization)
}
}

Expand All @@ -136,7 +129,7 @@ class BraintreeClient internal constructor(
analyticsClient.sendEvent(
it,
event,
integrationType,
merchantRepository.integrationType,
authorization
)
}
Expand All @@ -146,13 +139,13 @@ class BraintreeClient internal constructor(
* @suppress
*/
fun sendGET(url: String, responseCallback: HttpResponseCallback) {
if (authorization is InvalidAuthorization) {
if (merchantRepository.authorization is InvalidAuthorization) {
responseCallback.onResult(null, createAuthError())
return
}
getConfiguration { configuration, configError ->
if (configuration != null) {
httpClient.get(url, configuration, authorization) { response, httpError ->
httpClient.get(url, configuration, merchantRepository.authorization) { response, httpError ->
response?.let {
try {
sendAnalyticsTimingEvent(url, response.timing)
Expand Down Expand Up @@ -180,7 +173,7 @@ class BraintreeClient internal constructor(
additionalHeaders: Map<String, String> = emptyMap(),
responseCallback: HttpResponseCallback,
) {
if (authorization is InvalidAuthorization) {
if (merchantRepository.authorization is InvalidAuthorization) {
responseCallback.onResult(null, createAuthError())
return
}
Expand All @@ -190,7 +183,7 @@ class BraintreeClient internal constructor(
path = url,
data = data,
configuration = configuration,
authorization = authorization,
authorization = merchantRepository.authorization,
additionalHeaders = additionalHeaders
) { response, httpError ->
response?.let {
Expand All @@ -214,7 +207,7 @@ class BraintreeClient internal constructor(
* @suppress
*/
fun sendGraphQLPOST(json: JSONObject?, responseCallback: HttpResponseCallback) {
if (authorization is InvalidAuthorization) {
if (merchantRepository.authorization is InvalidAuthorization) {
responseCallback.onResult(null, createAuthError())
return
}
Expand All @@ -223,7 +216,7 @@ class BraintreeClient internal constructor(
graphQLClient.post(
json?.toString(),
configuration,
authorization
merchantRepository.authorization
) { response, httpError ->
response?.let {
try {
Expand Down Expand Up @@ -262,7 +255,7 @@ class BraintreeClient internal constructor(
return if (launchesBrowserSwitchAsNewTask) {
braintreeDeepLinkReturnUrlScheme
} else {
returnUrlScheme
merchantRepository.returnUrlScheme
}
}

Expand All @@ -271,7 +264,7 @@ class BraintreeClient internal constructor(
*/
fun <T> isUrlSchemeDeclaredInAndroidManifest(urlScheme: String?, klass: Class<T>?): Boolean {
return manifestValidator.isUrlSchemeDeclaredInAndroidManifest(
applicationContext,
merchantRepository.applicationContext,
urlScheme,
klass
)
Expand All @@ -281,7 +274,7 @@ class BraintreeClient internal constructor(
* @suppress
*/
fun <T> getManifestActivityInfo(klass: Class<T>?): ActivityInfo? {
return manifestValidator.getActivityInfo(applicationContext, klass)
return manifestValidator.getActivityInfo(merchantRepository.applicationContext, klass)
}

/**
Expand All @@ -290,10 +283,10 @@ class BraintreeClient internal constructor(
internal fun reportCrash() =
getConfiguration { configuration, _ ->
analyticsClient.reportCrash(
applicationContext,
merchantRepository.applicationContext,
configuration,
integrationType,
authorization
merchantRepository.integrationType,
merchantRepository.authorization
)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.braintreepayments.api.core

import android.content.Context
import android.net.Uri
import androidx.annotation.RestrictTo

/**
* An internal repository that holds properties set by the integrating merchant.
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
class MerchantRepository {

lateinit var applicationContext: Context
lateinit var integrationType: IntegrationType
lateinit var authorization: Authorization
lateinit var returnUrlScheme: String
var appLinkReturnUri: Uri? = null

companion object {

/**
* Singleton instance of the MerchantRepository.
*/
val instance: MerchantRepository by lazy { MerchantRepository() }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class BraintreeClientUnitTest {
private lateinit var manifestValidator: ManifestValidator
private lateinit var browserSwitchClient: BrowserSwitchClient
private lateinit var expectedAuthException: BraintreeException
private lateinit var merchantRepository: MerchantRepository

@Before
fun beforeEach() {
Expand All @@ -48,6 +49,7 @@ class BraintreeClientUnitTest {
analyticsClient = mockk(relaxed = true)
manifestValidator = mockk(relaxed = true)
browserSwitchClient = mockk(relaxed = true)
merchantRepository = mockk(relaxed = true)

val clientSDKSetupURL =
"https://developer.paypal.com/braintree/docs/guides/client-sdk/setup/android/v4#initialization"
Expand Down Expand Up @@ -402,24 +404,6 @@ class BraintreeClientUnitTest {
)
}

@Test
fun integrationType_returnsCustomByDefault() {
val context = ApplicationProvider.getApplicationContext<Context>()
val sut = BraintreeClient(context, authorization.toString())
assertEquals("custom", sut.integrationType.stringValue)
}

@Test
fun integrationType_returnsIntegrationTypeDefinedInConstructor() {
val context = ApplicationProvider.getApplicationContext<Context>()
val sut = BraintreeClient(
context = context,
authorization = authorization.toString(),
integrationType = IntegrationType.DROP_IN
)
assertEquals("dropin", sut.integrationType.stringValue)
}

@Test
@Throws(JSONException::class)
fun reportCrash_reportsCrashViaAnalyticsClient() {
Expand Down Expand Up @@ -447,20 +431,39 @@ class BraintreeClientUnitTest {
}
}

@Test
fun `when BraintreeClient is initialized, merchantRepository properties are set`() {
createBraintreeClient(merchantRepository = merchantRepository)
verify { merchantRepository.returnUrlScheme = "sample-return-url-scheme" }
verify { merchantRepository.applicationContext = applicationContext }
verify { merchantRepository.authorization = authorization }
verify { merchantRepository.appLinkReturnUri = Uri.parse("https://example.com") }
verify { merchantRepository.integrationType = IntegrationType.CUSTOM }
}

@Test
fun `when BraintreeClient is initialized and appLinkReturnUri is null, it is not set on the MerchantRepository`() {
createBraintreeClient(appLinkReturnUri = null, merchantRepository = merchantRepository)
verify(exactly = 0) { merchantRepository.appLinkReturnUri = null }
}

private fun createBraintreeClient(
configurationLoader: ConfigurationLoader,
time: Time = Time()
configurationLoader: ConfigurationLoader = mockk(),
time: Time = Time(),
appLinkReturnUri: Uri? = Uri.parse("https://example.com"),
merchantRepository: MerchantRepository = MerchantRepository.instance
) = BraintreeClient(
applicationContext = applicationContext,
integrationType = IntegrationType.CUSTOM,
authorization = authorization,
returnUrlScheme = "sample-return-url-scheme",
appLinkReturnUri = Uri.parse("https://example.com"),
appLinkReturnUri = appLinkReturnUri,
httpClient = braintreeHttpClient,
graphQLClient = braintreeGraphQLClient,
analyticsClient = analyticsClient,
manifestValidator = manifestValidator,
configurationLoader = configurationLoader,
time = time
time = time,
merchantRepository = merchantRepository,
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import com.braintreepayments.api.core.BraintreeClient
import com.braintreepayments.api.core.BraintreeException
import com.braintreepayments.api.core.Configuration
import com.braintreepayments.api.core.ErrorWithResponse.Companion.fromJson
import com.braintreepayments.api.core.MerchantRepository
import com.braintreepayments.api.core.MetadataBuilder
import com.braintreepayments.api.core.TokenizationKey
import com.braintreepayments.api.core.UserCanceledException
Expand All @@ -31,7 +32,8 @@ import org.json.JSONObject
class GooglePayClient internal constructor(
private val braintreeClient: BraintreeClient,
private val internalGooglePayClient: GooglePayInternalClient = GooglePayInternalClient(),
private val analyticsParamRepository: AnalyticsParamRepository = AnalyticsParamRepository.instance
private val analyticsParamRepository: AnalyticsParamRepository = AnalyticsParamRepository.instance,
private val merchantRepository: MerchantRepository = MerchantRepository.instance,
) {
/**
* Initializes a new [GooglePayClient] instance
Expand Down Expand Up @@ -154,7 +156,7 @@ class GooglePayClient internal constructor(
if (configuration != null) {
callback.onTokenizationParametersResult(
GooglePayTokenizationParameters.Success(
getTokenizationParameters(configuration, braintreeClient.authorization),
getTokenizationParameters(configuration, merchantRepository.authorization),
getAllowedCardNetworks(configuration)
)
)
Expand Down Expand Up @@ -201,7 +203,7 @@ class GooglePayClient internal constructor(
braintreeClient.getConfiguration { configuration: Configuration?, configError: Exception? ->

if (configuration?.isGooglePayEnabled == true) {
setGooglePayRequestDefaults(configuration, braintreeClient.authorization, request)
setGooglePayRequestDefaults(configuration, merchantRepository.authorization, request)

val paymentDataRequest =
PaymentDataRequest.fromJson(request.toJson())
Expand Down Expand Up @@ -315,7 +317,7 @@ class GooglePayClient internal constructor(
): PaymentMethodTokenizationParameters {

val metadata =
MetadataBuilder().integration(braintreeClient.integrationType)
MetadataBuilder().integration(merchantRepository.integrationType)
.sessionId(analyticsParamRepository.sessionId).version().build()

val version = try {
Expand Down Expand Up @@ -467,7 +469,7 @@ class GooglePayClient internal constructor(
.put("braintree:merchantId", configuration.merchantId)
.put(
"braintree:metadata", JSONObject().put("source", "client")
.put("integration", braintreeClient.integrationType)
.put("integration", merchantRepository.integrationType)
.put("sessionId", analyticsParamRepository.sessionId)
.put("version", googlePayVersion)
.put("platform", "android").toString()
Expand Down Expand Up @@ -507,7 +509,7 @@ class GooglePayClient internal constructor(
)
.put(
"braintree:metadata", JSONObject().put("source", "client")
.put("integration", braintreeClient.integrationType)
.put("integration", merchantRepository.integrationType)
.put("sessionId", analyticsParamRepository.sessionId)
.put("version", googlePayVersion)
.put("platform", "android").toString()
Expand Down
Loading

0 comments on commit ed09136

Please sign in to comment.