From e475b2e6a90aba4666044b6664584f1783a12796 Mon Sep 17 00:00:00 2001 From: Mo Mustafa Date: Fri, 18 Apr 2025 12:37:10 -0700 Subject: [PATCH 1/3] feat: Add support to forward SubscriptionGroupIds --- .../kotlin/com/mparticle/kits/AppboyKit.kt | 46 +++++++++++++++++-- src/test/kotlin/com/braze/BrazeUser.kt | 10 ++++ .../com/mparticle/kits/AppboyKitTest.kt | 19 ++++++++ 3 files changed, 72 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/com/mparticle/kits/AppboyKit.kt b/src/main/kotlin/com/mparticle/kits/AppboyKit.kt index f170d98..bb70226 100644 --- a/src/main/kotlin/com/mparticle/kits/AppboyKit.kt +++ b/src/main/kotlin/com/mparticle/kits/AppboyKit.kt @@ -47,6 +47,7 @@ open class AppboyKit : KitIntegration(), AttributeListener, CommerceListener, var bundleCommerceEvents = false var isMpidIdentityType = false var identityType: IdentityType? = null + var subscriptionGroupIds: MutableMap? = mutableMapOf() private val dataFlushHandler = Handler() private var dataFlushRunnable: Runnable? = null private var forwardScreenViews = false @@ -85,6 +86,9 @@ open class AppboyKit : KitIntegration(), AttributeListener, CommerceListener, } } forwardScreenViews = settings[FORWARD_SCREEN_VIEWS].toBoolean() + subscriptionGroupIds = settings[SUBSCRIPTION_GROUP_MAPPING]?.let { + getSubscriptionGroupIds(it) + } if (key != null) { val config = BrazeConfig.Builder().setApiKey(key) .setSdkFlavor(SdkFlavor.MPARTICLE) @@ -318,10 +322,27 @@ open class AppboyKit : KitIntegration(), AttributeListener, CommerceListener, else value.setGender(Gender.MALE) } else -> { - if (key.startsWith("$")) { - key = key.substring(1) + if (subscriptionGroupIds?.containsKey(key) == true) { + if (attributeValue == "true") { + value.addToSubscriptionGroup( + subscriptionGroupIds?.get(key).toString() + ) + } else if (attributeValue == "false") { + value.removeFromSubscriptionGroup( + subscriptionGroupIds?.get(key).toString() + ) + } else { + Logger.warning( + "unable to set Subscription Group ID for user attribute: " + + key + "due to invalid value data type. expected value data type should be Boolean" + ) + } + } else { + if (key.startsWith("$")) { + key = key.substring(1) + } + userAttributeSetter?.parseValue(key, attributeValue) } - userAttributeSetter?.parseValue(key, attributeValue) } } queueDataFlush() @@ -966,6 +987,24 @@ open class AppboyKit : KitIntegration(), AttributeListener, CommerceListener, return promotionArray } + private fun getSubscriptionGroupIds(subscriptionGroupMap: String): MutableMap { + val subscriptionGroupsArray = JSONArray(subscriptionGroupMap) + val subscriptionGroupIds = mutableMapOf() + + if (subscriptionGroupMap.isEmpty()) { + return subscriptionGroupIds + } + + for (i in 0 until subscriptionGroupsArray.length()) { + val subscriptionGroup = subscriptionGroupsArray.getJSONObject(i) + val key = subscriptionGroup.getString("map") + val value = subscriptionGroup.getString("value") + subscriptionGroupIds[key] = value + } + + return subscriptionGroupIds + } + fun getImpressionListParameters(impressionList: List): JSONArray { val impressionArray = JSONArray() for ((i, impression) in impressionList.withIndex()) { @@ -1083,6 +1122,7 @@ open class AppboyKit : KitIntegration(), AttributeListener, CommerceListener, const val USER_IDENTIFICATION_TYPE = "userIdentificationType" const val ENABLE_TYPE_DETECTION = "enableTypeDetection" const val BUNDLE_COMMERCE_EVENTS = "bundleCommerceEventData" + const val SUBSCRIPTION_GROUP_MAPPING = "subscriptionGroupMapping" const val HOST = "host" const val PUSH_ENABLED = "push_enabled" const val NAME = "Appboy" diff --git a/src/test/kotlin/com/braze/BrazeUser.kt b/src/test/kotlin/com/braze/BrazeUser.kt index 71fdd40..97be7cf 100644 --- a/src/test/kotlin/com/braze/BrazeUser.kt +++ b/src/test/kotlin/com/braze/BrazeUser.kt @@ -58,6 +58,16 @@ class BrazeUser { return true } + fun addToSubscriptionGroup(key: String): Boolean { + customUserAttributes[key] = true + return true + } + + fun removeFromSubscriptionGroup(key: String): Boolean { + customUserAttributes[key] = false + return true + } + fun getCustomAttribute(): HashMap> { return customAttributeArray } diff --git a/src/test/kotlin/com/mparticle/kits/AppboyKitTest.kt b/src/test/kotlin/com/mparticle/kits/AppboyKitTest.kt index e409aad..b3ade6b 100644 --- a/src/test/kotlin/com/mparticle/kits/AppboyKitTest.kt +++ b/src/test/kotlin/com/mparticle/kits/AppboyKitTest.kt @@ -238,6 +238,25 @@ class AppboyKitTests { Assert.assertNull(kit.getCalendarMinusYears(-1)) } + @Test + fun testSetSubscriptionGroupIds() { + val settings = HashMap() + settings[AppboyKit.APPBOY_KEY] = "key" + settings[AppboyKit.HOST] = hostName + settings["subscriptionGroupMapping"] = "" + + "[{\"jsmap\":null,\"map\":\"test1\",\"maptype\":\"UserAttributeClass.Name\",\"value\":\"00000000-0000-0000-0000-000000000000\"}," + + "{\"jsmap\":null,\"map\":\"test2\",\"maptype\":\"UserAttributeClass.Name\",\"value\":\"00000000-0000-0000-0000-000000000001\"}," + + "{\"jsmap\":null,\"map\":\"test3\",\"maptype\":\"UserAttributeClass.Name\",\"value\":\"00000000-0000-0000-0000-000000000002\"}]" + val kit = MockAppboyKit() + val currentUser = braze.currentUser + + kit.onKitCreate(settings, MockContextApplication()) + kit.setUserAttribute("test1", "true"); + kit.setUserAttribute("test2", "false"); + kit.setUserAttribute("test3", "notABoolean"); + Assert.assertEquals(2, currentUser.getCustomUserAttribute().size.toLong()) + } + // @Test // fun testSetUserAttributeAge() { // val currentYear = Calendar.getInstance()[Calendar.YEAR] From 3975f4ce8ddfbfacd119dbdb6b35bd12285a7aed Mon Sep 17 00:00:00 2001 From: Mo Mustafa Date: Wed, 23 Apr 2025 10:52:15 -0700 Subject: [PATCH 2/3] cleaner code change --- .../kotlin/com/mparticle/kits/AppboyKit.kt | 47 ++++++++++--------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/src/main/kotlin/com/mparticle/kits/AppboyKit.kt b/src/main/kotlin/com/mparticle/kits/AppboyKit.kt index bb70226..74c1c24 100644 --- a/src/main/kotlin/com/mparticle/kits/AppboyKit.kt +++ b/src/main/kotlin/com/mparticle/kits/AppboyKit.kt @@ -323,19 +323,19 @@ open class AppboyKit : KitIntegration(), AttributeListener, CommerceListener, } else -> { if (subscriptionGroupIds?.containsKey(key) == true) { - if (attributeValue == "true") { - value.addToSubscriptionGroup( - subscriptionGroupIds?.get(key).toString() - ) - } else if (attributeValue == "false") { - value.removeFromSubscriptionGroup( - subscriptionGroupIds?.get(key).toString() - ) - } else { - Logger.warning( - "unable to set Subscription Group ID for user attribute: " - + key + "due to invalid value data type. expected value data type should be Boolean" - ) + val groupId = subscriptionGroupIds?.get(key) + when (attributeValue.lowercase()) { + "true" -> { + groupId?.let { value.addToSubscriptionGroup(it) } + } + "false" -> { + groupId?.let { value.removeFromSubscriptionGroup(it) } + } + else -> { + Logger.warning( + "Unable to set Subscription Group ID for user attribute: $key due to invalid value data type. Expected Boolean." + ) + } } } else { if (key.startsWith("$")) { @@ -988,21 +988,26 @@ open class AppboyKit : KitIntegration(), AttributeListener, CommerceListener, } private fun getSubscriptionGroupIds(subscriptionGroupMap: String): MutableMap { - val subscriptionGroupsArray = JSONArray(subscriptionGroupMap) val subscriptionGroupIds = mutableMapOf() if (subscriptionGroupMap.isEmpty()) { return subscriptionGroupIds } - for (i in 0 until subscriptionGroupsArray.length()) { - val subscriptionGroup = subscriptionGroupsArray.getJSONObject(i) - val key = subscriptionGroup.getString("map") - val value = subscriptionGroup.getString("value") - subscriptionGroupIds[key] = value - } + val subscriptionGroupsArray = JSONArray(subscriptionGroupMap) - return subscriptionGroupIds + return try{ + for (i in 0 until subscriptionGroupsArray.length()) { + val subscriptionGroup = subscriptionGroupsArray.getJSONObject(i) + val key = subscriptionGroup.getString("map") + val value = subscriptionGroup.getString("value") + subscriptionGroupIds[key] = value + } + subscriptionGroupIds + } catch (e: JSONException) { + Logger.warning("Braze, unable to parse \"subscriptionGroup\"") + mutableMapOf() + } } fun getImpressionListParameters(impressionList: List): JSONArray { From 340aa9cc678f4c7e0ce9655d0795c81353058e8c Mon Sep 17 00:00:00 2001 From: Mo Mustafa Date: Wed, 23 Apr 2025 13:26:17 -0700 Subject: [PATCH 3/3] code formatting --- src/main/kotlin/com/mparticle/kits/AppboyKit.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/com/mparticle/kits/AppboyKit.kt b/src/main/kotlin/com/mparticle/kits/AppboyKit.kt index 74c1c24..3002ded 100644 --- a/src/main/kotlin/com/mparticle/kits/AppboyKit.kt +++ b/src/main/kotlin/com/mparticle/kits/AppboyKit.kt @@ -328,9 +328,11 @@ open class AppboyKit : KitIntegration(), AttributeListener, CommerceListener, "true" -> { groupId?.let { value.addToSubscriptionGroup(it) } } + "false" -> { groupId?.let { value.removeFromSubscriptionGroup(it) } } + else -> { Logger.warning( "Unable to set Subscription Group ID for user attribute: $key due to invalid value data type. Expected Boolean." @@ -996,7 +998,7 @@ open class AppboyKit : KitIntegration(), AttributeListener, CommerceListener, val subscriptionGroupsArray = JSONArray(subscriptionGroupMap) - return try{ + return try { for (i in 0 until subscriptionGroupsArray.length()) { val subscriptionGroup = subscriptionGroupsArray.getJSONObject(i) val key = subscriptionGroup.getString("map")