From b44d038a3c74688198e0c8bbc67440ef5d9fdcb9 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 22 Jan 2024 12:36:57 +0000 Subject: [PATCH] fix: Added support for identify with JWT --- .../com/extole/blackbox/sdk/ExtoleSdkTests.kt | 156 ++++++++++++++++++ config/detekt.yml | 4 +- mobile-sdk/build.gradle | 8 +- .../java/com/extole/android/sdk/Extole.kt | 6 +- .../extole/android/sdk/impl/CampaignImpl.kt | 17 +- .../com/extole/android/sdk/impl/ExtoleImpl.kt | 13 +- 6 files changed, 193 insertions(+), 11 deletions(-) diff --git a/app/src/androidTest/java/com/extole/blackbox/sdk/ExtoleSdkTests.kt b/app/src/androidTest/java/com/extole/blackbox/sdk/ExtoleSdkTests.kt index 527d7af..7a59e45 100644 --- a/app/src/androidTest/java/com/extole/blackbox/sdk/ExtoleSdkTests.kt +++ b/app/src/androidTest/java/com/extole/blackbox/sdk/ExtoleSdkTests.kt @@ -14,6 +14,7 @@ import org.apache.commons.lang3.RandomStringUtils import org.assertj.core.api.Assertions.assertThat import org.awaitility.Awaitility.await import org.awaitility.Duration +import org.json.JSONObject import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -258,4 +259,159 @@ class ExtoleSdkTests { assertThat(initialTime).isBefore(timeAfterIdentify) } + @Test + fun testIdentifyJwtWillFlushCache() { + val jwt = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6IjUzNmQwNWE2LTMzZWUtNDI2NC04ODI2LW" + + "JhZDRjOTAyMWZhZiJ9.eyJpc3MiOiJtb2JpbGUtc2RrLmV4dG9sZS5jb20iLCJhdWQiOlsiZXh0b2xlLmNvbSJ" + + "dLCJlbWFpbCI6InNka3BlcnNvbi1lbWFpbEBtYWlsb3NhdXIuY29tIiwiaWF0IjoxNzA1NTg0Mjg0LCJleHAiO" + + "jI0ODMxODQyODR9.XdB5-j58GcEeKqKkCLd5f_G78CLLJIHCmsfcOpH-n3o" + val extole = + runBlocking { + return@runBlocking Extole.init( + "mobile-monitor.extole.io", + context = context, appName = "mobile-monitor", labels = setOf("business"), + data = mapOf("version" to "1.0"), + ) + } + + + val initialTimeStampValue = runBlocking { + val (ctaZone, _) = extole.fetchZone("mobile_cta_timestamp") + val initialTimestampValue = ctaZone?.get("timestamp") + initialTimestampValue as Long + } + + val emailBeforeIdentify = runBlocking { + val (ctaZone, _) = extole.fetchZone("mobile_cta_timestamp") + ctaZone?.get("email").toString() + } + + assertThat(emailBeforeIdentify).isEqualTo("null") + + runBlocking { + extole.identifyJwt(jwt) + } + + val timeStampValueAfterIdentify = runBlocking { + val (ctaZone, _) = extole.fetchZone("mobile_cta_timestamp") + val initialTimestampValue = ctaZone?.get("timestamp") + initialTimestampValue as Long + } + + val initialTime = Instant.ofEpochSecond(initialTimeStampValue) + val timeAfterIdentify = Instant.ofEpochSecond(timeStampValueAfterIdentify) + assertThat(initialTime).isBefore(timeAfterIdentify) + + + val emailAfterIdentify = runBlocking { + val (ctaZone, _) = extole.fetchZone("mobile_cta_timestamp") + ctaZone?.get("email") as String + } + + assertThat(emailAfterIdentify).isEqualTo("sdkperson-email@mailosaur.com") + } + + @Test + fun testIdentifyJwtWithoutEmail() { + val jwt = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6IjUzNmQwNWE2LTMzZWUtNDI2NC04ODI2" + + "LWJhZDRjOTAyMWZhZiJ9.eyJpc3MiOiJtb2JpbGUtc2RrLmV4dG9sZS5jb20iLCJhdWQiOlsiZXh0b2xlLmN" + + "vbSJdLCJpYXQiOjE3MDU5MjQwMDksImV4cCI6MjQ4MzUyNDAwOX0.X2GnR6OV9amojSLSzoXeecoujrnMzyY" + + "As5VWzR86U4M"; + + val extole = + runBlocking { + return@runBlocking Extole.init( + "mobile-monitor.extole.io", + context = context, appName = "mobile-monitor", labels = setOf("business"), + data = mapOf("version" to "1.0"), + ) + } + + + val initialTimeStampValue = runBlocking { + val (ctaZone, _) = extole.fetchZone("mobile_cta_timestamp") + val initialTimestampValue = ctaZone?.get("timestamp") + initialTimestampValue as Long + } + + val emailBeforeIdentify = runBlocking { + val (ctaZone, _) = extole.fetchZone("mobile_cta_timestamp") + ctaZone?.get("email").toString() + } + + assertThat(emailBeforeIdentify).isEqualTo("null") + + runBlocking { + extole.identifyJwt(jwt) + } + + val timeStampValueAfterIdentify = runBlocking { + val (ctaZone, _) = extole.fetchZone("mobile_cta_timestamp") + val initialTimestampValue = ctaZone?.get("timestamp") + initialTimestampValue as Long + } + + val initialTime = Instant.ofEpochSecond(initialTimeStampValue) + val timeAfterIdentify = Instant.ofEpochSecond(timeStampValueAfterIdentify) + assertThat(initialTime).isEqualTo(timeAfterIdentify) + + + val emailAfterIdentify = runBlocking { + val (ctaZone, _) = extole.fetchZone("mobile_cta_timestamp") + ctaZone?.get("email").toString() + } + + assertThat(emailAfterIdentify).isEqualTo("null") + } + + @Test + fun testIdentifyWithInvalidJwt() { + val jwt = "invalid_jwt"; + + val extole = + runBlocking { + return@runBlocking Extole.init( + "mobile-monitor.extole.io", + context = context, appName = "mobile-monitor", labels = setOf("business"), + data = mapOf("version" to "1.0"), + ) + } + + + val initialTimeStampValue = runBlocking { + val (ctaZone, _) = extole.fetchZone("mobile_cta_timestamp") + val initialTimestampValue = ctaZone?.get("timestamp") + initialTimestampValue as Long + } + + val emailBeforeIdentify = runBlocking { + val (ctaZone, _) = extole.fetchZone("mobile_cta_timestamp") + ctaZone?.get("email").toString() + } + + assertThat(emailBeforeIdentify).isEqualTo("null") + + runBlocking { + extole.identifyJwt(jwt) + } + + val timeStampValueAfterIdentify = runBlocking { + val (ctaZone, _) = extole.fetchZone("mobile_cta_timestamp") + val initialTimestampValue = ctaZone?.get("timestamp") + initialTimestampValue as Long + } + + val initialTime = Instant.ofEpochSecond(initialTimeStampValue) + val timeAfterIdentify = Instant.ofEpochSecond(timeStampValueAfterIdentify) + assertThat(initialTime).isEqualTo(timeAfterIdentify) + + + val emailAfterIdentify = runBlocking { + val (ctaZone, _) = extole.fetchZone("mobile_cta_timestamp") + ctaZone?.get("email").toString() + } + + assertThat(emailAfterIdentify).isEqualTo("null") + } + } diff --git a/config/detekt.yml b/config/detekt.yml index 5813196..55d1410 100644 --- a/config/detekt.yml +++ b/config/detekt.yml @@ -127,8 +127,8 @@ complexity: TooManyFunctions: active: true excludes: ['**/test/**', '**/androidTest/**', '**/commonTest/**'] - thresholdInFiles: 30 - thresholdInClasses: 30 + thresholdInFiles: 35 + thresholdInClasses: 35 thresholdInInterfaces: 15 thresholdInObjects: 15 thresholdInEnums: 15 diff --git a/mobile-sdk/build.gradle b/mobile-sdk/build.gradle index 90b52ae..3ec9ec0 100644 --- a/mobile-sdk/build.gradle +++ b/mobile-sdk/build.gradle @@ -26,14 +26,14 @@ detekt { } android { - compileSdkVersion 33 + compileSdkVersion 34 buildToolsVersion '31.0.0' defaultConfig { minSdkVersion 21 - targetSdkVersion 33 - versionCode 46 - versionName "1.0.48" + targetSdkVersion 34 + versionCode 47 + versionName "1.0.49" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" consumerProguardFiles "consumer-rules.pro" diff --git a/mobile-sdk/src/main/java/com/extole/android/sdk/Extole.kt b/mobile-sdk/src/main/java/com/extole/android/sdk/Extole.kt index 49c643f..53a0579 100644 --- a/mobile-sdk/src/main/java/com/extole/android/sdk/Extole.kt +++ b/mobile-sdk/src/main/java/com/extole/android/sdk/Extole.kt @@ -58,7 +58,8 @@ interface Extole { @Throws(RestException::class) suspend fun sendEvent( eventName: String, - data: Map = emptyMap() + data: Map = emptyMap(), + jwt: String? = null ): Id /** @@ -70,6 +71,9 @@ interface Extole { @Throws(RestException::class) suspend fun identify(identifier: String, data: Map = mapOf()): Id + @Throws(RestException::class) + suspend fun identifyJwt(jwt: String, data: Map = mapOf()): Id + /** * Used to clear cache and remove current access_token */ diff --git a/mobile-sdk/src/main/java/com/extole/android/sdk/impl/CampaignImpl.kt b/mobile-sdk/src/main/java/com/extole/android/sdk/impl/CampaignImpl.kt index 5e66a06..e823161 100644 --- a/mobile-sdk/src/main/java/com/extole/android/sdk/impl/CampaignImpl.kt +++ b/mobile-sdk/src/main/java/com/extole/android/sdk/impl/CampaignImpl.kt @@ -73,7 +73,11 @@ class CampaignImpl( return requestData } - override suspend fun sendEvent(eventName: String, data: Map): Id { + override suspend fun sendEvent( + eventName: String, + data: Map, + jwt: String? + ): Id { try { val requestData = mutableMapOf() requestData.putAll(data) @@ -83,6 +87,9 @@ class CampaignImpl( val requestBody = mutableMapOf() requestBody["event_name"] = eventName requestBody["data"] = requestData + jwt?.let { + requestBody["jwt"] = it + } return Id( extole.getServices().getEventsEndpoints().post(requestBody).entity.getString("id") ) @@ -97,8 +104,12 @@ class CampaignImpl( } } - override suspend fun identify(email: String, data: Map): Id { - return extole.identify(email, data) + override suspend fun identify(identifier: String, data: Map): Id { + return extole.identify(identifier, data) + } + + override suspend fun identifyJwt(jwt: String, data: Map): Id { + return extole.identifyJwt(jwt, data) } override fun logout() { diff --git a/mobile-sdk/src/main/java/com/extole/android/sdk/impl/ExtoleImpl.kt b/mobile-sdk/src/main/java/com/extole/android/sdk/impl/ExtoleImpl.kt index 85d369e..e13f07c 100644 --- a/mobile-sdk/src/main/java/com/extole/android/sdk/impl/ExtoleImpl.kt +++ b/mobile-sdk/src/main/java/com/extole/android/sdk/impl/ExtoleImpl.kt @@ -110,7 +110,11 @@ class ExtoleImpl( override fun getContext(): ApplicationContext = context - override suspend fun sendEvent(eventName: String, data: Map): Id { + override suspend fun sendEvent( + eventName: String, + data: Map, + jwt: String? + ): Id { EventBus.getDefault().post(AppEvent(eventName, data)) try { val requestData = mutableMapOf() @@ -119,6 +123,9 @@ class ExtoleImpl( val requestBody = mutableMapOf() requestBody["event_name"] = eventName requestBody["data"] = requestData + jwt?.let { + requestBody["jwt"] = it + } val httpPostResult = extoleServices.getEventsEndpoints().post(requestBody) val accessTokenHeader = httpPostResult.headers.entries @@ -159,6 +166,10 @@ class ExtoleImpl( return sendEvent(IDENTIFY_EVENT_NAME, identifyData) } + override suspend fun identifyJwt(jwt: String, data: Map): Id { + return sendEvent(IDENTIFY_EVENT_NAME, data, jwt) + } + override suspend fun clone( programDomain: String?, appName: String?,