Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MOB-9559] implements identity resolution #800

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import com.iterable.iterableapi.IterableApi;
import com.iterable.iterableapi.IterableConfig;
import com.iterable.iterableapi.IterableConstants;
import com.iterable.iterableapi.IterableIdentityResolution;
import com.iterable.iterableapi.testapp.R;
import org.json.JSONArray;
import org.json.JSONException;
Expand Down Expand Up @@ -113,15 +114,13 @@ protected void onCreate(Bundle savedInstanceState) {
});
findViewById(R.id.setUser).setOnClickListener(view -> {
EditText setUser_edit = findViewById(R.id.setUser_edit);
if(setUser_edit == null) return;
final Boolean mergeFlag = ((CheckBox) findViewById(R.id.user_check)).isChecked();
IterableApi.getInstance().setUserId(String.valueOf(setUser_edit.getText()), mergeFlag);
if(setUser_edit == null) return;;
IterableApi.getInstance().setUserId(String.valueOf(setUser_edit.getText()));
});
findViewById(R.id.setEmail).setOnClickListener(view -> {
EditText setEmail_edit = findViewById(R.id.setEmail_edit);
if(setEmail_edit == null) return;
final Boolean mergeFlag = ((CheckBox) findViewById(R.id.email_check)).isChecked();
IterableApi.getInstance().setEmail(String.valueOf(setEmail_edit.getText()), mergeFlag);
IterableApi.getInstance().setEmail(String.valueOf(setEmail_edit.getText()));
});

findViewById(R.id.btn_logout).setOnClickListener(view -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
public class AnonymousUserMerge {
private static final String TAG = "AnonymousUserMerge";

void tryMergeUser(IterableApiClient apiClient, String anonymousUserId, String destinationUser, boolean isEmail, boolean merge, boolean shouldUserDefaultMerge, MergeResultCallback callback) {
void tryMergeUser(IterableApiClient apiClient, String anonymousUserId, String destinationUser, boolean isEmail, boolean merge, MergeResultCallback callback) {
evantk91 marked this conversation as resolved.
Show resolved Hide resolved
IterableLogger.v(TAG, "tryMergeUser");
if (anonymousUserId != null && (shouldUserDefaultMerge || merge)) {
if (anonymousUserId != null && merge) {
String destinationEmail = isEmail ? destinationUser : null;
String destinationUserId = isEmail ? null : destinationUser;
apiClient.mergeUser(null, anonymousUserId, destinationEmail, destinationUserId, data -> {
Expand Down
104 changes: 56 additions & 48 deletions iterableapi/src/main/java/com/iterable/iterableapi/IterableApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -733,44 +733,36 @@ public void pauseAuthRetries(boolean pauseRetry) {
}

public void setEmail(@Nullable String email) {
setEmail(email, null, false, true, null, null);
setEmail(email, null, null, null, null);
evantk91 marked this conversation as resolved.
Show resolved Hide resolved
}

public void setEmail(@Nullable String email, boolean merge) {
setEmail(email, null, merge, false, null, null);
public void setEmail(@Nullable String email, IterableIdentityResolution identityResolution) {
setEmail(email, null, identityResolution, null, null);
}

public void setEmail(@Nullable String email, @Nullable IterableHelper.SuccessHandler successHandler, @Nullable IterableHelper.FailureHandler failureHandler) {
setEmail(email, null, false, true, successHandler, failureHandler);
setEmail(email, null, null, successHandler, failureHandler);
}

public void setEmail(@Nullable String email, boolean merge, @Nullable IterableHelper.SuccessHandler successHandler, @Nullable IterableHelper.FailureHandler failureHandler) {
setEmail(email, null, merge, false, successHandler, failureHandler);
public void setEmail(@Nullable String email, IterableIdentityResolution identityResolution, @Nullable IterableHelper.SuccessHandler successHandler, @Nullable IterableHelper.FailureHandler failureHandler) {
setEmail(email, null, identityResolution, successHandler, failureHandler);
}

public void setEmail(@Nullable String email, @Nullable String authToken) {
setEmail(email, authToken, false, true, null, null);
setEmail(email, authToken, null, null, null);
}

public void setEmail(@Nullable String email, @Nullable String authToken, boolean merge) {
setEmail(email, authToken, merge, false, null, null);
public void setEmail(@Nullable String email, @Nullable String authToken, IterableIdentityResolution identityResolution) {
setEmail(email, authToken, identityResolution, null, null);
}

public void setEmail(@Nullable String email, @Nullable String authToken, @Nullable IterableHelper.SuccessHandler successHandler, @Nullable IterableHelper.FailureHandler failureHandler) {
setEmail(email, authToken, false, true, successHandler, failureHandler);
setEmail(email, authToken, null, successHandler, failureHandler);
}

public void setEmail(@Nullable String email, @Nullable String authToken, boolean merge, @Nullable IterableHelper.SuccessHandler successHandler, @Nullable IterableHelper.FailureHandler failureHandler) {
setEmail(email, authToken, merge, false, successHandler, failureHandler);
}

private void setEmail(@Nullable String email, @Nullable String authToken, boolean merge, boolean shouldUseDefaultMerge, @Nullable IterableHelper.SuccessHandler successHandler, @Nullable IterableHelper.FailureHandler failureHandler) {
if (config.enableAnonTracking) {
if (email != null) {
attemptAndProcessMerge(email, true, merge, shouldUseDefaultMerge, failureHandler, _userIdAnon);
}
_userIdAnon = null;
}
public void setEmail(@Nullable String email, @Nullable String authToken, @Nullable IterableIdentityResolution iterableIdentityResolution, @Nullable IterableHelper.SuccessHandler successHandler, @Nullable IterableHelper.FailureHandler failureHandler) {
boolean replay = isReplay(iterableIdentityResolution);
boolean merge = isMerge(iterableIdentityResolution);

if (_email != null && _email.equals(email)) {
checkAndUpdateAuthToken(authToken);
Expand All @@ -785,6 +777,14 @@ private void setEmail(@Nullable String email, @Nullable String authToken, boolea

_email = email;
_userId = null;

if (config.enableAnonTracking) {
if (email != null) {
attemptAndProcessMerge(email, true, merge, replay, failureHandler, _userIdAnon);
}
_userIdAnon = null;
}

_setUserSuccessCallbackHandler = successHandler;
_setUserFailureCallbackHandler = failureHandler;
storeAuthData();
Expand All @@ -794,52 +794,42 @@ private void setEmail(@Nullable String email, @Nullable String authToken, boolea

public void setAnonUser(@Nullable String userId) {
_userIdAnon = userId;
setUserId(userId, null, false, true, null, null, true);
setUserId(userId, null, null, null, null, true);
storeAuthData();
}

public void setUserId(@Nullable String userId) {
setUserId(userId, null, false, true, null, null, false);
setUserId(userId, null, null, null, null, false);
}

public void setUserId(@Nullable String userId, boolean merge) {
setUserId(userId, null, merge, false, null, null, false);
public void setUserId(@Nullable String userId, IterableIdentityResolution identityResolution) {
setUserId(userId, null, identityResolution, null, null, false);
}

public void setUserId(@Nullable String userId, @Nullable IterableHelper.SuccessHandler successHandler, @Nullable IterableHelper.FailureHandler failureHandler) {
setUserId(userId, null, false, true, successHandler, failureHandler, false);
setUserId(userId, null, null, successHandler, failureHandler, false);
}

public void setUserId(@Nullable String userId, boolean merge, @Nullable IterableHelper.SuccessHandler successHandler, @Nullable IterableHelper.FailureHandler failureHandler) {
setUserId(userId, null, merge, false, successHandler, failureHandler, false);
public void setUserId(@Nullable String userId, IterableIdentityResolution identityResolution, @Nullable IterableHelper.SuccessHandler successHandler, @Nullable IterableHelper.FailureHandler failureHandler) {
setUserId(userId, null, identityResolution, successHandler, failureHandler, false);
}

public void setUserId(@Nullable String userId, @Nullable String authToken) {
setUserId(userId, authToken, false, true, null, null, false);
setUserId(userId, authToken, null, null, null, false);
}

public void setUserId(@Nullable String userId, @Nullable String authToken, boolean merge) {
setUserId(userId, authToken, merge, false, null, null, false);
public void setUserId(@Nullable String userId, @Nullable String authToken, IterableIdentityResolution identityResolution) {
setUserId(userId, authToken, identityResolution, null, null, false);

}

public void setUserId(@Nullable String userId, @Nullable String authToken, @Nullable IterableHelper.SuccessHandler successHandler, @Nullable IterableHelper.FailureHandler failureHandler) {
setUserId(userId, authToken, false, true, successHandler, failureHandler, false);
setUserId(userId, authToken, null, successHandler, failureHandler, false);
}

public void setUserId(@Nullable String userId, @Nullable String authToken, boolean merge, @Nullable IterableHelper.SuccessHandler successHandler, @Nullable IterableHelper.FailureHandler failureHandler) {
setUserId(userId, authToken, merge, false, successHandler, failureHandler, false);
}

private void setUserId(@Nullable String userId, @Nullable String authToken, boolean merge, boolean shouldUseDefaultMerge, @Nullable IterableHelper.SuccessHandler successHandler, @Nullable IterableHelper.FailureHandler failureHandler, boolean isAnon) {
if (config.enableAnonTracking) {
if (userId != null && !userId.equals(_userIdAnon)) {
attemptAndProcessMerge(userId, false, merge, shouldUseDefaultMerge, failureHandler, _userIdAnon);
}
if (!isAnon) {
_userIdAnon = null;
}
}
public void setUserId(@Nullable String userId, @Nullable String authToken, @Nullable IterableIdentityResolution iterableIdentityResolution, @Nullable IterableHelper.SuccessHandler successHandler, @Nullable IterableHelper.FailureHandler failureHandler, boolean isAnon) {
boolean replay = isReplay(iterableIdentityResolution);
boolean merge = isMerge(iterableIdentityResolution);

if (_userId != null && _userId.equals(userId)) {
checkAndUpdateAuthToken(authToken);
Expand All @@ -854,17 +844,35 @@ private void setUserId(@Nullable String userId, @Nullable String authToken, bool

_email = null;
_userId = userId;

if (config.enableAnonTracking) {
if (userId != null && !userId.equals(_userIdAnon)) {
attemptAndProcessMerge(userId, false, merge, replay, failureHandler, _userIdAnon);
}
if (!isAnon) {
_userIdAnon = null;
evantk91 marked this conversation as resolved.
Show resolved Hide resolved
}
}

_setUserSuccessCallbackHandler = successHandler;
_setUserFailureCallbackHandler = failureHandler;
storeAuthData();

onLogin(authToken);
}

private void attemptAndProcessMerge(@NonNull String destinationUser, boolean isEmail, boolean merge, boolean shouldUseDefaultMerge, IterableHelper.FailureHandler failureHandler, String anonymousUserId) {
anonymousUserMerge.tryMergeUser(apiClient, anonymousUserId, destinationUser, isEmail, merge, shouldUseDefaultMerge, (mergeResult, error) -> {
private boolean isMerge(@Nullable IterableIdentityResolution iterableIdentityResolution) {
return (iterableIdentityResolution != null) ? iterableIdentityResolution.getMergeOnAnonymousToKnown() : config.identityResolution.getMergeOnAnonymousToKnown();
}

private boolean isReplay(@Nullable IterableIdentityResolution iterableIdentityResolution) {
return (iterableIdentityResolution != null) ? iterableIdentityResolution.getReplayOnVisitorToKnown() : config.identityResolution.getReplayOnVisitorToKnown();
}

private void attemptAndProcessMerge(@NonNull String destinationUser, boolean isEmail, boolean merge, boolean replay, IterableHelper.FailureHandler failureHandler, String anonymousUserId) {
anonymousUserMerge.tryMergeUser(apiClient, anonymousUserId, destinationUser, isEmail, merge, (mergeResult, error) -> {
if (mergeResult == IterableConstants.MERGE_SUCCESSFUL || mergeResult == IterableConstants.MERGE_NOTREQUIRED) {
if (shouldUseDefaultMerge || merge) {
if (replay) {
anonymousUserManager.syncEvents();
}
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,12 @@ public class IterableConfig {
*/
final boolean enableEmbeddedMessaging;

/**
* This controls whether the SDK should allow event replay from local storage to logged in profile
* and merging between the generated anonymous profile and the logged in profile by default.
*/
final IterableIdentityResolution identityResolution;

private IterableConfig(Builder builder) {
pushIntegrationName = builder.pushIntegrationName;
urlHandler = builder.urlHandler;
Expand All @@ -117,6 +123,7 @@ private IterableConfig(Builder builder) {
enableAnonTracking = builder.enableAnonTracking;
enableEmbeddedMessaging = builder.enableEmbeddedMessaging;
eventThresholdLimit = builder.eventThresholdLimit;
identityResolution = builder.identityResolution;
}

public static class Builder {
Expand All @@ -138,6 +145,7 @@ public static class Builder {
private boolean enableAnonTracking = false;
private boolean enableEmbeddedMessaging = false;
private int eventThresholdLimit = 100;
private IterableIdentityResolution identityResolution = new IterableIdentityResolution();

public Builder() {}

Expand Down Expand Up @@ -325,6 +333,19 @@ public Builder setEnableEmbeddedMessaging(boolean enableEmbeddedMessaging) {
return this;
}

/**
* Set whether the SDK should replay events from local storage to the logged in profile
* and set whether the SDK should merge the generated anonymous profile and the logged in profile.
* This can be overwritten by a parameter passed into setEmail or setUserId.
* @param identityResolution
* @return
*/

public Builder setIdentityResolution(IterableIdentityResolution identityResolution) {
this.identityResolution = identityResolution;
return this;
}

@NonNull
public IterableConfig build() {
return new IterableConfig(this);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.iterable.iterableapi

data class IterableIdentityResolution (
val replayOnVisitorToKnown: Boolean = true,
val mergeOnAnonymousToKnown: Boolean = true
)
evantk91 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,10 @@ public void testCustomEventTrackApi() throws Exception {
addResponse(IterableConstants.ENDPOINT_TRACK_ANON_SESSION);
addResponse(IterableConstants.ENDPOINT_TRACK);
final String userId = "testUser2";
IterableApi.getInstance().setUserId(userId, false);

evantk91 marked this conversation as resolved.
Show resolved Hide resolved
IterableIdentityResolution identityRes = new IterableIdentityResolution(true, false);
IterableApi.getInstance().setUserId(userId, identityRes);

while (server.takeRequest(1, TimeUnit.SECONDS) != null) { }
JSONObject customEventItem = new JSONObject("{\n" +
" \"dataFields\": " +
Expand Down
Loading
Loading