Skip to content

Commit 498575f

Browse files
feat: map selected identity 'emailsha256' (#601)
1 parent 41bb52f commit 498575f

3 files changed

Lines changed: 143 additions & 14 deletions

File tree

android-kit-base/src/main/java/com/mparticle/kits/KitConfiguration.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ public class KitConfiguration {
6262
private final static String KEY_CONSENT_FORWARDING_RULES_VALUE_HASH = "h";
6363
private final static String KEY_EXCLUDE_ANONYMOUS_USERS = "eau";
6464
private final static String KEY_PLACEMENT_ATTRIBUTES_MAPPING = "placementAttributesMapping";
65+
private final static String KEY_HASHED_EMAIL_IDENTITY_TYPE= "hashedEmailUserIdentityType";
6566

6667
//If set to true, our sdk honor user's optout wish. If false, we still collect data on opt-ed out users, but only for reporting.
6768
private final static String HONOR_OPT_OUT = "honorOptOut";
@@ -995,6 +996,10 @@ public JSONArray getPlacementAttributesMapping() throws JSONException {
995996
return new JSONArray(jsonArrayStr);
996997
}
997998

999+
public String getHashedEmailUserIdentityType() {
1000+
return settings.get(KEY_HASHED_EMAIL_IDENTITY_TYPE);
1001+
}
1002+
9981003
boolean shouldSetIdentity(MParticle.IdentityType identityType) {
9991004
SparseBooleanArray userIdentityFilters = getUserIdentityFilters();
10001005
return userIdentityFilters == null ||

android-kit-base/src/main/java/com/mparticle/kits/KitManagerImpl.java

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1364,7 +1364,8 @@ public void execute(@NonNull String viewName,
13641364
String email = getValueIgnoreCase(attributes, "email");
13651365
String hashedEmail = getValueIgnoreCase(attributes, "emailsha256");
13661366
Map<String, String> tempAttributes = attributes;
1367-
confirmEmail(email, hashedEmail, user, instance.Identity(), () -> {
1367+
KitConfiguration kitConfig = provider.getConfiguration();
1368+
confirmEmail(email, hashedEmail, user, instance.Identity(), kitConfig, () -> {
13681369
Map<String, String> finalAttributes = prepareAttributes(provider, tempAttributes, user);
13691370

13701371
((KitIntegration.RoktListener) provider).execute(viewName,
@@ -1497,7 +1498,8 @@ public void prepareAttributesAsync(@NonNull Map<String, String> attributes) {
14971498
String email = attributes.get("email");
14981499
String hashedEmail = getValueIgnoreCase(attributes, "emailsha256");
14991500
Map<String, String> tempAttributes = attributes;
1500-
confirmEmail(email, hashedEmail, user, instance.Identity(), () -> {
1501+
KitConfiguration kitConfig = provider.getConfiguration();
1502+
confirmEmail(email, hashedEmail, user, instance.Identity(), kitConfig, () -> {
15011503
Map<String, String> finalAttributes = prepareAttributes(provider, tempAttributes, user);
15021504
((KitIntegration.RoktListener) provider).enrichAttributes(
15031505
finalAttributes, FilteredMParticleUser.getInstance(user.getId(), provider));
@@ -1514,19 +1516,30 @@ private void confirmEmail(
15141516
@Nullable String hashedEmail,
15151517
@Nullable MParticleUser user,
15161518
IdentityApi identityApi,
1519+
KitConfiguration kitConfiguration,
15171520
Runnable runnable
15181521
) {
15191522
boolean hasEmail = email != null && !email.isEmpty();
15201523
boolean hasHashedEmail = hashedEmail != null && !hashedEmail.isEmpty();
15211524

15221525
if ((hasEmail || hasHashedEmail) && user != null) {
1526+
MParticle.IdentityType selectedIdentityType = null;
1527+
try {
1528+
String identityTypeStr = (kitConfiguration != null)
1529+
? kitConfiguration.getHashedEmailUserIdentityType()
1530+
: null;
1531+
if (identityTypeStr != null ) {
1532+
selectedIdentityType = MParticle.IdentityType.valueOf(identityTypeStr);
1533+
}
1534+
} catch (IllegalArgumentException e) {
1535+
Logger.error("Invalid identity type "+e.getMessage());
1536+
}
15231537
String existingEmail = user.getUserIdentities().get(MParticle.IdentityType.Email);
1524-
String existingHashedEmail = user.getUserIdentities().get(MParticle.IdentityType.Other);
1525-
1538+
String existingHashedEmail = selectedIdentityType != null ? user.getUserIdentities().get(selectedIdentityType) : null;
15261539
boolean emailMismatch = hasEmail && !email.equalsIgnoreCase(existingEmail);
15271540
boolean hashedEmailMismatch = hasHashedEmail && !hashedEmail.equalsIgnoreCase(existingHashedEmail);
15281541

1529-
if (emailMismatch || hashedEmailMismatch) {
1542+
if (emailMismatch || (hashedEmailMismatch && selectedIdentityType != null)) {
15301543
// If there's an existing email but it doesn't match the passed-in email, log a warning
15311544
if (emailMismatch && existingEmail != null) {
15321545
Logger.warning(String.format(
@@ -1551,7 +1564,7 @@ else if (hashedEmailMismatch && existingHashedEmail != null) {
15511564
identityBuilder.email(email);
15521565
}
15531566
if (hashedEmailMismatch) {
1554-
identityBuilder.userIdentity(MParticle.IdentityType.Other, hashedEmail);
1567+
identityBuilder.userIdentity(selectedIdentityType, hashedEmail);
15551568
}
15561569

15571570
IdentityApiRequest identityRequest = identityBuilder.build();

android-kit-base/src/test/kotlin/com/mparticle/kits/KitManagerImplTest.kt

Lines changed: 119 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1105,10 +1105,11 @@ class KitManagerImplTest {
11051105
String::class.java,
11061106
MParticleUser::class.java,
11071107
IdentityApi::class.java,
1108+
KitConfiguration::class.java,
11081109
Runnable::class.java
11091110
)
11101111
method.isAccessible = true
1111-
val result = method.invoke(manager, "Test@gmail.com", "", user, identityApi, runnable)
1112+
val result = method.invoke(manager, "Test@gmail.com", "", user, identityApi, mockedKitConfig, runnable)
11121113
verify(mockTask).addSuccessListener(any())
11131114
}
11141115

@@ -1153,10 +1154,11 @@ class KitManagerImplTest {
11531154
String::class.java,
11541155
MParticleUser::class.java,
11551156
IdentityApi::class.java,
1157+
KitConfiguration::class.java,
11561158
Runnable::class.java
11571159
)
11581160
method.isAccessible = true
1159-
val result = method.invoke(manager, "Test@gmail.com", null, user, identityApi, runnable)
1161+
val result = method.invoke(manager, "Test@gmail.com", null, user, identityApi, mockedKitConfig, runnable)
11601162
verify(runnable).run()
11611163
}
11621164

@@ -1201,10 +1203,11 @@ class KitManagerImplTest {
12011203
String::class.java,
12021204
MParticleUser::class.java,
12031205
IdentityApi::class.java,
1206+
KitConfiguration::class.java,
12041207
Runnable::class.java
12051208
)
12061209
method.isAccessible = true
1207-
val result = method.invoke(manager, null, null, user, identityApi, runnable)
1210+
val result = method.invoke(manager, null, null, user, identityApi, mockedKitConfig, runnable)
12081211
verify(runnable).run()
12091212
}
12101213

@@ -1249,10 +1252,11 @@ class KitManagerImplTest {
12491252
String::class.java,
12501253
MParticleUser::class.java,
12511254
IdentityApi::class.java,
1255+
KitConfiguration::class.java,
12521256
Runnable::class.java
12531257
)
12541258
method.isAccessible = true
1255-
val result = method.invoke(manager, "", "", user, identityApi, runnable)
1259+
val result = method.invoke(manager, "", "", user, identityApi, mockedKitConfig, runnable)
12561260
verify(runnable).run()
12571261
}
12581262

@@ -1297,11 +1301,12 @@ class KitManagerImplTest {
12971301
String::class.java,
12981302
MParticleUser::class.java,
12991303
IdentityApi::class.java,
1304+
KitConfiguration::class.java,
13001305
Runnable::class.java
13011306
)
13021307
method.isAccessible = true
1303-
val result = method.invoke(manager, "", "hashed_Test@gmail.com", user, identityApi, runnable)
1304-
verify(mockTask).addSuccessListener(any())
1308+
val result = method.invoke(manager, "", "hashed_Test@gmail.com", user, identityApi, mockedKitConfig, runnable)
1309+
verify(runnable).run()
13051310
}
13061311

13071312
@Test
@@ -1345,10 +1350,11 @@ class KitManagerImplTest {
13451350
String::class.java,
13461351
MParticleUser::class.java,
13471352
IdentityApi::class.java,
1353+
KitConfiguration::class.java,
13481354
Runnable::class.java
13491355
)
13501356
method.isAccessible = true
1351-
val result = method.invoke(manager, null, "hashed_Test@gmail.com", user, identityApi, runnable)
1357+
val result = method.invoke(manager, null, "hashed_Test@gmail.com", user, identityApi, mockedKitConfig, runnable)
13521358
verify(runnable).run()
13531359
}
13541360

@@ -1393,10 +1399,115 @@ class KitManagerImplTest {
13931399
String::class.java,
13941400
MParticleUser::class.java,
13951401
IdentityApi::class.java,
1402+
KitConfiguration::class.java,
1403+
Runnable::class.java
1404+
)
1405+
method.isAccessible = true
1406+
val result = method.invoke(manager, null, null, user, identityApi, mockedKitConfig, runnable)
1407+
verify(runnable).run()
1408+
}
1409+
1410+
@Test
1411+
fun testConfirmHashedEmail_When_HashedEmailUserIdentityType_Is_Other3() {
1412+
var runnable: Runnable = mock(Runnable::class.java)
1413+
var user: MParticleUser = mock(MParticleUser::class.java)
1414+
val instance = MockMParticle()
1415+
val sideloadedKit = mock(MPSideloadedKit::class.java)
1416+
val kitId = 6000000
1417+
1418+
val configJSONObj = JSONObject().apply {
1419+
put("id", kitId)
1420+
}
1421+
val mockedKitConfig = KitConfiguration.createKitConfiguration(configJSONObj)
1422+
1423+
`when`(mockedKitConfig.hashedEmailUserIdentityType).thenReturn("Other3")
1424+
`when`(sideloadedKit.configuration).thenReturn(mockedKitConfig)
1425+
val identityApi = mock(IdentityApi::class.java)
1426+
val oldHashedEmail = "hashed_old@example.com"
1427+
val mockTask = mock(MParticleTask::class.java) as MParticleTask<IdentityApiResult>
1428+
`when`(identityApi.identify(any())).thenReturn(mockTask)
1429+
val identities: MutableMap<MParticle.IdentityType, String> = HashMap()
1430+
identities.put(MParticle.IdentityType.Other, oldHashedEmail)
1431+
`when`(user.userIdentities).thenReturn(identities)
1432+
instance.setIdentityApi(identityApi)
1433+
val settingsMap = hashMapOf(
1434+
"placementAttributesMapping" to """
1435+
[
1436+
// add placement attributes here if needed
1437+
]
1438+
""".trimIndent(),
1439+
"hashedEmailUserIdentityType" to "Other3"
1440+
)
1441+
val field = KitConfiguration::class.java.getDeclaredField("settings")
1442+
field.isAccessible = true
1443+
field.set(mockedKitConfig, settingsMap)
1444+
1445+
val options = MParticleOptions.builder(MockContext())
1446+
.sideloadedKits(mutableListOf(sideloadedKit) as List<SideloadedKit>).build()
1447+
val manager: KitManagerImpl = MockKitManagerImpl(options)
1448+
val method: Method = KitManagerImpl::class.java.getDeclaredMethod(
1449+
"confirmEmail",
1450+
String::class.java,
1451+
String::class.java,
1452+
MParticleUser::class.java,
1453+
IdentityApi::class.java,
1454+
KitConfiguration::class.java,
1455+
Runnable::class.java
1456+
)
1457+
method.isAccessible = true
1458+
val result = method.invoke(manager, "", "hashed_Test@gmail.com", user, identityApi, mockedKitConfig, runnable)
1459+
verify(mockTask).addSuccessListener(any())
1460+
}
1461+
1462+
@Test
1463+
fun testConfirmHashedEmail_When_HashedEmailUserIdentityType_Is_Unknown() {
1464+
var runnable: Runnable = mock(Runnable::class.java)
1465+
var user: MParticleUser = mock(MParticleUser::class.java)
1466+
val instance = MockMParticle()
1467+
val sideloadedKit = mock(MPSideloadedKit::class.java)
1468+
val kitId = 6000000
1469+
1470+
val configJSONObj = JSONObject().apply {
1471+
put("id", kitId)
1472+
}
1473+
val mockedKitConfig = KitConfiguration.createKitConfiguration(configJSONObj)
1474+
1475+
`when`(mockedKitConfig.hashedEmailUserIdentityType).thenReturn("Unknown")
1476+
`when`(sideloadedKit.configuration).thenReturn(mockedKitConfig)
1477+
val identityApi = mock(IdentityApi::class.java)
1478+
val oldHashedEmail = "hashed_old@example.com"
1479+
val mockTask = mock(MParticleTask::class.java) as MParticleTask<IdentityApiResult>
1480+
`when`(identityApi.identify(any())).thenReturn(mockTask)
1481+
val identities: MutableMap<MParticle.IdentityType, String> = HashMap()
1482+
identities.put(MParticle.IdentityType.Other, oldHashedEmail)
1483+
`when`(user.userIdentities).thenReturn(identities)
1484+
instance.setIdentityApi(identityApi)
1485+
val settingsMap = hashMapOf(
1486+
"placementAttributesMapping" to """
1487+
[
1488+
// add placement attributes here if needed
1489+
]
1490+
""".trimIndent(),
1491+
"hashedEmailUserIdentityType" to "Unknown"
1492+
)
1493+
val field = KitConfiguration::class.java.getDeclaredField("settings")
1494+
field.isAccessible = true
1495+
field.set(mockedKitConfig, settingsMap)
1496+
1497+
val options = MParticleOptions.builder(MockContext())
1498+
.sideloadedKits(mutableListOf(sideloadedKit) as List<SideloadedKit>).build()
1499+
val manager: KitManagerImpl = MockKitManagerImpl(options)
1500+
val method: Method = KitManagerImpl::class.java.getDeclaredMethod(
1501+
"confirmEmail",
1502+
String::class.java,
1503+
String::class.java,
1504+
MParticleUser::class.java,
1505+
IdentityApi::class.java,
1506+
KitConfiguration::class.java,
13961507
Runnable::class.java
13971508
)
13981509
method.isAccessible = true
1399-
val result = method.invoke(manager, null, null, user, identityApi, runnable)
1510+
val result = method.invoke(manager, "", "hashed_Test@gmail.com", user, identityApi, mockedKitConfig, runnable)
14001511
verify(runnable).run()
14011512
}
14021513

0 commit comments

Comments
 (0)