From b7b746fcfe80d159bf69d46dcbaa0d32b3226476 Mon Sep 17 00:00:00 2001 From: Grant Black <85238976+grablack@users.noreply.github.com> Date: Wed, 20 Mar 2024 13:25:56 -0400 Subject: [PATCH] refactor: prevent empty values (#29) --- .../java/com/paypal/messages/io/ApiTest.kt | 50 ++++++++++++++--- .../main/java/com/paypal/messages/io/Api.kt | 56 ++++++++++++++++++- 2 files changed, 95 insertions(+), 11 deletions(-) diff --git a/library/src/androidTest/java/com/paypal/messages/io/ApiTest.kt b/library/src/androidTest/java/com/paypal/messages/io/ApiTest.kt index d3d52328..0c44ae67 100644 --- a/library/src/androidTest/java/com/paypal/messages/io/ApiTest.kt +++ b/library/src/androidTest/java/com/paypal/messages/io/ApiTest.kt @@ -8,6 +8,7 @@ import com.paypal.messages.config.PayPalEnvironment import com.paypal.messages.config.PayPalMessageOfferType import com.paypal.messages.config.message.PayPalMessageData import com.paypal.messages.config.message.PayPalMessageStyle +import com.paypal.messages.io.Api.preventEmptyValues import com.paypal.messages.utils.PayPalErrors import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.cancel @@ -18,6 +19,8 @@ import kotlinx.coroutines.test.runTest import okhttp3.mockwebserver.MockResponse import okhttp3.mockwebserver.MockWebServer import org.junit.After +import org.junit.Assert.assertFalse +import org.junit.Assert.assertNotEquals import org.junit.Assert.assertNotNull import org.junit.Assert.assertTrue import org.junit.Before @@ -68,16 +71,14 @@ class ApiTest { val expectedPath = "credit-presentment/native/message" val expectedQueryParts = arrayOf( "client_id=test_client_id", - "devTouchpoint=false", - "ignore_cache=false", "instance_id", "session_id", ) assertTrue(url.contains(expectedPath)) assertTrue(url.contains("client_id=test_client_id")) - assertTrue(url.contains("devTouchpoint=false")) - assertTrue(url.contains("ignore_cache=false")) + assertFalse(url.contains("devTouchpoint=false")) + assertFalse(url.contains("ignore_cache=false")) assertTrue(url.contains("instance_id")) assertTrue(url.contains("session_id")) expectedQueryParts.forEach { assertTrue(url.contains(it)) } @@ -100,8 +101,6 @@ class ApiTest { val expectedPath = "credit-presentment/native/message" val expectedQueryParts = arrayOf( "client_id=test_client_id", - "devTouchpoint=false", - "ignore_cache=false", "instance_id", "session_id", "amount=1.0", @@ -112,8 +111,6 @@ class ApiTest { assertTrue(url.contains(expectedPath)) assertTrue(url.contains("client_id=test_client_id")) - assertTrue(url.contains("devTouchpoint=false")) - assertTrue(url.contains("ignore_cache=false")) assertTrue(url.contains("instance_id")) assertTrue(url.contains("session_id")) assertTrue(url.contains("amount=1.0")) @@ -308,4 +305,41 @@ class ApiTest { val expectedPath = "v1/credit/upstream-messaging-events" assertTrue(request.url.toString().contains(expectedPath)) } + + @Test + fun testEmptyValuesInSerialization() { + val payloadJson = """ + { + "data":{ + "client_id":"", + "components":[ + { + "__shared__":{}, + "amount":"null", + "channel":"NATIVE", + "component_events":[], + "style_color":"BLACK", + "style_logo_type":"PRIMARY", + "style_text_align":"LEFT", + "type":"MESSAGE" + } + ], + "device_id":"android_id", + "integration_type":"NATIVE_ANDROID", + "integration_name": "", + "integration_version": "" + } + } + """.trimIndent() + + val updated = preventEmptyValues(payloadJson) + + assertNotEquals(payloadJson, updated) + assertFalse(updated.contains("integration_name")) + assertFalse(updated.contains("integration_version")) + + assertFalse(updated.contains("__shared__")) + assertFalse(updated.contains("amount")) + assertFalse(updated.contains("component_events")) + } } diff --git a/library/src/main/java/com/paypal/messages/io/Api.kt b/library/src/main/java/com/paypal/messages/io/Api.kt index a3b5810b..66e24bde 100644 --- a/library/src/main/java/com/paypal/messages/io/Api.kt +++ b/library/src/main/java/com/paypal/messages/io/Api.kt @@ -17,6 +17,7 @@ import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.RequestBody.Companion.toRequestBody import okio.IOException +import org.json.JSONObject import java.util.UUID import com.paypal.messages.config.PayPalEnvironment as Env import com.paypal.messages.config.PayPalMessageOfferType as OfferType @@ -40,8 +41,8 @@ object Api { instanceId: UUID, ) { addQueryParameter("client_id", config.data.clientID) - addQueryParameter("devTouchpoint", devTouchpoint.toString()) - addQueryParameter("ignore_cache", ignoreCache.toString()) + devTouchpoint.toString()?.takeIf { it != "false" }?.let { addQueryParameter("devTouchpoint", it) } + ignoreCache.toString()?.takeIf { it != "false" }?.let { addQueryParameter("ignore_cache", it) } addQueryParameter("instance_id", instanceId.toString()) addQueryParameter("session_id", sessionId.toString()) @@ -227,9 +228,58 @@ object Api { return request } + fun preventEmptyValues(json: String): String { + fun checkIfEmpty(value: String): Boolean { + return (value == "{}" || value == "[]" || value == "null" || value == "") + } + + val jsonObject = JSONObject(json) + + val obj = jsonObject.getJSONObject("data") + + val integrationName = obj.get("integration_name") + if (checkIfEmpty(integrationName.toString())) { + obj.remove("integration_name") + } + + val integrationVersion = obj.get("integration_version") + if (checkIfEmpty(integrationName.toString())) { + obj.remove("integration_version") + } + + val components = obj.getJSONArray("components") + val comp = components.getJSONObject(0) + + val keysToRemove = mutableListOf() + + val keys = comp.keys() + while (keys.hasNext()) { + val key = keys.next() + val componentValue = comp.get(key) + + if (checkIfEmpty(componentValue.toString())) { + keysToRemove.add(key) + } + } + + // Remove marked keys + for (key in keysToRemove) { + comp.remove(key) + } + + // Put the modified components back into obj + components.put(0, comp) + obj.put("components", components) + + // Update the jsonObject if necessary + jsonObject.put("data", obj) + + return jsonObject.toString() + } + fun callLoggerEndpoint(payload: TrackingPayload) { val json = gson.toJson(CloudEvent(data = payload)) - val request = createLoggerRequest(json) + val request = createLoggerRequest(preventEmptyValues(json)) val response = client.newCall(request).execute() response.body?.string()?.let { LogCat.debug(TAG, "callLoggerEndpoint response: $it") } }