From 409bf8ed08fb79a796e9563b69c144f9c786c815 Mon Sep 17 00:00:00 2001 From: Alexander Sapountzis Date: Wed, 25 Oct 2023 17:25:57 -0400 Subject: [PATCH 1/9] fix: Split out logout function from onUserIdentified --- src/MixpanelEventForwarder.js | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/MixpanelEventForwarder.js b/src/MixpanelEventForwarder.js index 775bd1e..39be89b 100644 --- a/src/MixpanelEventForwarder.js +++ b/src/MixpanelEventForwarder.js @@ -137,6 +137,24 @@ var constructor = function () { } } + function onLogoutComplete() { + if (!isInitialized) { + return ( + 'Cannot call logout on forwarder: ' + + name + + ', not initialized' + ); + } + + try { + mixpanel.mparticle.reset(); + + return 'Successfully called reset on forwarder: ' + name; + } catch (e) { + return 'Cannot call reset on forwarder: ' + name + ': ' + e; + } + } + function onUserIdentified(user) { var idForMixpanel; var userIdentities = user.getUserIdentities() @@ -245,8 +263,17 @@ var constructor = function () { this.process = processEvent; this.setUserAttribute = setUserAttribute; this.setUserIdentity = setUserIdentity; - this.onUserIdentified = onUserIdentified; this.removeUserAttribute = removeUserAttribute; + + // For all Identity Requests, we run mixpanel.identify( Date: Wed, 25 Oct 2023 17:52:44 -0400 Subject: [PATCH 2/9] Update tests --- test/src/tests.js | 232 +++++++++++++++++++++++++++++++++------------- 1 file changed, 166 insertions(+), 66 deletions(-) diff --git a/test/src/tests.js b/test/src/tests.js index a99a286..9a54857 100644 --- a/test/src/tests.js +++ b/test/src/tests.js @@ -104,6 +104,10 @@ describe('Mixpanel Forwarder', function () { setCalledAttributes(data, 'identifyCalled'); }; + this.mparticle.reset = function (data) { + setCalledAttributes(data, 'resetCalled'); + }; + this.mparticle.alias = function (data) { setCalledAttributes(data, 'aliasCalled'); }; @@ -284,15 +288,72 @@ describe('Mixpanel Forwarder', function () { done(); }); - it('should identify user (mParticle SDK v2)', function (done) { - mParticle.forwarder.init( + it('should log in a user (mParticle SDK v2)', function (done) { + + var user = { + getUserIdentities: function () { + return { + userIdentities: { + customerid: 'cust1', + other: 'other1', + other2: 'other2', + other3: 'other3', + other4: 'other4', + }, + }; + }, + getMPID: function () { + return 'mpid1'; + }, + }; + + var identificationTypes = [ { - includeUserAttributes: 'True', userIdentificationType: 'CustomerId', + expectedProperty: 'cust1' }, - reportService.cb, - true - ); + { + userIdentificationType: 'Other', + expectedProperty: 'other1' + }, + { + userIdentificationType: 'Other2', + expectedProperty: 'other2' + }, + { + userIdentificationType: 'Other3', + expectedProperty: 'other3' + }, + { + userIdentificationType: 'Other4', + expectedProperty: 'other4' + }, + ]; + + identificationTypes.forEach(function (identificationType) { + mParticle.forwarder.init( + { + includeUserAttributes: 'True', + userIdentificationType: identificationType.userIdentificationType + }, + reportService.cb, + true + ); + + mParticle.forwarder.onLoginComplete(user); + window.mixpanel.mparticle.should.have.property( + 'identifyCalled', + true + ); + window.mixpanel.mparticle.should.have.property('data', identificationType.expectedProperty); + + }); + + done(); + }); + + it('should identify a user (mParticle SDK v2)', function (done) { + var user = { getUserIdentities: function () { return { @@ -310,92 +371,131 @@ describe('Mixpanel Forwarder', function () { }, }; - mParticle.forwarder.onUserIdentified(user); - window.mixpanel.mparticle.should.have.property( - 'identifyCalled', - true - ); - window.mixpanel.mparticle.should.have.property('data', 'cust1'); - - mParticle.forwarder.init( + var identificationTypes = [ { - includeUserAttributes: 'True', - userIdentificationType: 'MPID', + userIdentificationType: 'CustomerId', + expectedProperty: 'cust1' }, - reportService.cb, - true - ); - - mParticle.forwarder.onUserIdentified(user); - window.mixpanel.mparticle.should.have.property( - 'identifyCalled', - true - ); - window.mixpanel.mparticle.should.have.property('data', 'mpid1'); - - mParticle.forwarder.init( { - includeUserAttributes: 'True', userIdentificationType: 'Other', + expectedProperty: 'other1' }, - reportService.cb, - true - ); - - mParticle.forwarder.onUserIdentified(user); - window.mixpanel.mparticle.should.have.property( - 'identifyCalled', - true - ); - window.mixpanel.mparticle.should.have.property('data', 'other1'); - - mParticle.forwarder.init( { - includeUserAttributes: 'True', userIdentificationType: 'Other2', + expectedProperty: 'other2' }, - reportService.cb, - true - ); + { + userIdentificationType: 'Other3', + expectedProperty: 'other3' + }, + { + userIdentificationType: 'Other4', + expectedProperty: 'other4' + }, + ]; + + identificationTypes.forEach(function (identificationType) { + mParticle.forwarder.init( + { + includeUserAttributes: 'True', + userIdentificationType: identificationType.userIdentificationType + }, + reportService.cb, + true + ); + + mParticle.forwarder.onIdentifyComplte(user); + window.mixpanel.mparticle.should.have.property( + 'identifyCalled', + true + ); + window.mixpanel.mparticle.should.have.property('data', identificationType.expectedProperty); - mParticle.forwarder.onUserIdentified(user); - window.mixpanel.mparticle.should.have.property( - 'identifyCalled', - true - ); - window.mixpanel.mparticle.should.have.property('data', 'other2'); + }); - mParticle.forwarder.init( + done(); + }); + + it('should modify a user\'s identity (mParticle SDK v2)', function (done) { + + var user = { + getUserIdentities: function () { + return { + userIdentities: { + customerid: 'cust1', + other: 'other1', + other2: 'other2', + other3: 'other3', + other4: 'other4', + }, + }; + }, + getMPID: function () { + return 'mpid1'; + }, + }; + + var identificationTypes = [ + { + userIdentificationType: 'CustomerId', + expectedProperty: 'cust1' + }, + { + userIdentificationType: 'Other', + expectedProperty: 'other1' + }, + { + userIdentificationType: 'Other2', + expectedProperty: 'other2' + }, { - includeUserAttributes: 'True', userIdentificationType: 'Other3', + expectedProperty: 'other3' }, - reportService.cb, - true - ); + { + userIdentificationType: 'Other4', + expectedProperty: 'other4' + }, + ]; + + identificationTypes.forEach(function (identificationType) { + mParticle.forwarder.init( + { + includeUserAttributes: 'True', + userIdentificationType: identificationType.userIdentificationType + }, + reportService.cb, + true + ); + + mParticle.forwarder.onModifyComplete(user); + window.mixpanel.mparticle.should.have.property( + 'identifyCalled', + true + ); + window.mixpanel.mparticle.should.have.property('data', identificationType.expectedProperty); - mParticle.forwarder.onUserIdentified(user); - window.mixpanel.mparticle.should.have.property( - 'identifyCalled', - true - ); - window.mixpanel.mparticle.should.have.property('data', 'other3'); + }); + + done(); + }); + + it('should log out a user (mParticle SDK v2)', function (done) { mParticle.forwarder.init( { includeUserAttributes: 'True', - userIdentificationType: 'Other4', + userIdentificationType: 'MPID' }, reportService.cb, true ); - mParticle.forwarder.onUserIdentified(user); + mParticle.forwarder.onLogoutComplete(); window.mixpanel.mparticle.should.have.property( - 'identifyCalled', + 'resetCalled', true ); - window.mixpanel.mparticle.should.have.property('data', 'other4'); done(); }); From a4a7bfd571fbf039204a99512be8278cd75d04fb Mon Sep 17 00:00:00 2001 From: Alexander Sapountzis Date: Fri, 27 Oct 2023 13:07:00 -0400 Subject: [PATCH 3/9] Update onLoginComplete to require user identities and update tests --- src/MixpanelEventForwarder.js | 50 +++++++--- test/src/tests.js | 174 ++++++++++++++++------------------ 2 files changed, 122 insertions(+), 102 deletions(-) diff --git a/src/MixpanelEventForwarder.js b/src/MixpanelEventForwarder.js index 39be89b..ad37b0c 100644 --- a/src/MixpanelEventForwarder.js +++ b/src/MixpanelEventForwarder.js @@ -137,12 +137,31 @@ var constructor = function () { } } + function getUserIdentities(user) { + return user.getUserIdentities() + ? user.getUserIdentities().userIdentities + : {}; + } + + function onLoginComplete(user) { + var userIdentities = getUserIdentities(user); + + // When mParticle identifies a user, the user might + // actually be anonymous. We only want to send an + // identify request to Mixpanel if the user is + // actually known. Only known (logged in) users + // will have userIdentities. + if (!isEmpty(userIdentities)) { + sendIdentifyRequest(user, userIdentities); + } else { + return 'Logged in user does not have user identities and will not be sent to Mixpanel to Identify'; + } + } + function onLogoutComplete() { if (!isInitialized) { return ( - 'Cannot call logout on forwarder: ' + - name + - ', not initialized' + 'Cannot call logout on forwarder: ' + name + ', not initialized' ); } @@ -155,11 +174,13 @@ var constructor = function () { } } - function onUserIdentified(user) { + function sendIdentifyRequest(user, userIdentities) { var idForMixpanel; - var userIdentities = user.getUserIdentities() - ? user.getUserIdentities().userIdentities - : {}; + + if (isEmpty(userIdentities)) { + userIdentities = getUserIdentities(user); + } + switch (forwarderSettings.userIdentificationType) { case 'CustomerId': idForMixpanel = userIdentities.customerid; @@ -264,16 +285,19 @@ var constructor = function () { this.setUserAttribute = setUserAttribute; this.setUserIdentity = setUserIdentity; this.removeUserAttribute = removeUserAttribute; - + + this.onLoginComplete = onLoginComplete; + // For all Identity Requests, we run mixpanel.identify( Date: Fri, 27 Oct 2023 15:06:22 -0400 Subject: [PATCH 4/9] Address PR Comments --- src/MixpanelEventForwarder.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/MixpanelEventForwarder.js b/src/MixpanelEventForwarder.js index ad37b0c..118936c 100644 --- a/src/MixpanelEventForwarder.js +++ b/src/MixpanelEventForwarder.js @@ -13,6 +13,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +// ** Glossary of terms +// Mixpanel Terms: +// user_id: A unique identifier used by the Mixpanel.identify method to identify a unique user +// device_id: A unique identifier used by Mixpanel to identify an anonymous user, usually a guid +// distinct_id: A unique identifier that Mixpanel uses to bridge a user and a device. Usually the +// distinct_id has a prefix of $device:guid to denote an anonymouse user +// and this will be replaced by the user_id once the user has been identified by +// a request to Mixpanel.identify + // eslint-disable-next-line no-redeclare var name = 'MixpanelEventForwarder', moduleId = 10, @@ -288,15 +297,15 @@ var constructor = function () { this.onLoginComplete = onLoginComplete; - // For all Identity Requests, we run mixpanel.identify() // as per Mixpanel's documentation https://docs.mixpanel.com/docs/tracking-methods/identifying-users // except when a user logs out, where we run mixpanel.reset() to - // detach the distinct_id from the device_id + // detach the Mixpanel distinct_id from the Mixpanel device_id this.onLogoutComplete = onLogoutComplete; // For these two methods, we are essentially passing along the // Identify request the same way. - this.onIdentifyComplte = sendIdentifyRequest; + this.onIdentifyComplete = sendIdentifyRequest; this.onModifyComplete = sendIdentifyRequest; }; From 6c4cade3cfefb279da7c26813c562c0168813fea Mon Sep 17 00:00:00 2001 From: Alexander Sapountzis Date: Fri, 27 Oct 2023 17:26:55 -0400 Subject: [PATCH 5/9] Address PR Comments --- src/MixpanelEventForwarder.js | 55 ++++++++++++++++++++++++++--------- test/src/tests.js | 2 +- 2 files changed, 43 insertions(+), 14 deletions(-) diff --git a/src/MixpanelEventForwarder.js b/src/MixpanelEventForwarder.js index 118936c..349a744 100644 --- a/src/MixpanelEventForwarder.js +++ b/src/MixpanelEventForwarder.js @@ -168,6 +168,11 @@ var constructor = function () { } function onLogoutComplete() { + // For all Identity Requests, we run mixpanel.identify() + // as per Mixpanel's documentation https://docs.mixpanel.com/docs/tracking-methods/identifying-users + // except when a user logs out, where we run mixpanel.reset() to + // detach the Mixpanel distinct_id from the Mixpanel device_id + if (!isInitialized) { return ( 'Cannot call logout on forwarder: ' + name + ', not initialized' @@ -183,13 +188,45 @@ var constructor = function () { } } - function sendIdentifyRequest(user, userIdentities) { - var idForMixpanel; + function onIdentifyComplete(user) { + // When mParticle identifies a user, the user might + // actually be anonymous. We only want to send an + // identify request to Mixpanel if the user is + // actually known. Only known (logged in) users + // will have userIdentities. + var userIdentities = getUserIdentities(user); + + if (!isEmpty(userIdentities)) { + sendIdentifyRequest(user, userIdentities); + } else { + return 'User is anonymous'; + } + } + function onModifyComplete(user) { + // Mixpanel does not have the concept of modifying a + // user's identity. For the time being, we will rely on + // doing a simple Mixpanel.identify request. However + // this method may be deprecated in a future release + var userIdentities = getUserIdentities(user); + + if (!isEmpty(userIdentities)) { + sendIdentifyRequest(user, userIdentities); + } else { + return 'User is anonymous'; + } + } + + function sendIdentifyRequest(user, userIdentities) { + // We should only make Mixpanel.identify requests + // when a user has userIdentities and is therefore + // a known mParticle user and not anonymous if (isEmpty(userIdentities)) { - userIdentities = getUserIdentities(user); + return; } + var idForMixpanel; + switch (forwarderSettings.userIdentificationType) { case 'CustomerId': idForMixpanel = userIdentities.customerid; @@ -295,18 +332,10 @@ var constructor = function () { this.setUserIdentity = setUserIdentity; this.removeUserAttribute = removeUserAttribute; + this.onIdentifyComplete = onIdentifyComplete; this.onLoginComplete = onLoginComplete; - - // For all Identity Requests, we run mixpanel.identify() - // as per Mixpanel's documentation https://docs.mixpanel.com/docs/tracking-methods/identifying-users - // except when a user logs out, where we run mixpanel.reset() to - // detach the Mixpanel distinct_id from the Mixpanel device_id this.onLogoutComplete = onLogoutComplete; - - // For these two methods, we are essentially passing along the - // Identify request the same way. - this.onIdentifyComplete = sendIdentifyRequest; - this.onModifyComplete = sendIdentifyRequest; + this.onModifyComplete = onModifyComplete; }; function getId() { diff --git a/test/src/tests.js b/test/src/tests.js index 55c3781..cf077d9 100644 --- a/test/src/tests.js +++ b/test/src/tests.js @@ -419,7 +419,7 @@ describe('Mixpanel Forwarder', function () { true ); - mParticle.forwarder.onIdentifyComplte(user); + mParticle.forwarder.onIdentifyComplete(user); window.mixpanel.mparticle.should.have.property( 'identifyCalled', true From 43d06c711e620632ed47b0be005672ca11d56678 Mon Sep 17 00:00:00 2001 From: Alex S <49695018+alexs-mparticle@users.noreply.github.com> Date: Mon, 30 Oct 2023 18:59:36 -0400 Subject: [PATCH 6/9] Update src/MixpanelEventForwarder.js Co-authored-by: Robert Ing --- src/MixpanelEventForwarder.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MixpanelEventForwarder.js b/src/MixpanelEventForwarder.js index 349a744..797a288 100644 --- a/src/MixpanelEventForwarder.js +++ b/src/MixpanelEventForwarder.js @@ -15,7 +15,7 @@ // ** Glossary of terms // Mixpanel Terms: -// user_id: A unique identifier used by the Mixpanel.identify method to identify a unique user +// user_id: A unique identifier used by the Mixpanel.identify method to identify a unique user. This will map to what an mParticle customer selects in the UI, which translates to the forwarderSettings.userIdentificationType. // device_id: A unique identifier used by Mixpanel to identify an anonymous user, usually a guid // distinct_id: A unique identifier that Mixpanel uses to bridge a user and a device. Usually the // distinct_id has a prefix of $device:guid to denote an anonymouse user From 3604b0b74a6b1dff09c34ee4802c1ac6ef590ff5 Mon Sep 17 00:00:00 2001 From: Alex S <49695018+alexs-mparticle@users.noreply.github.com> Date: Mon, 30 Oct 2023 19:00:21 -0400 Subject: [PATCH 7/9] Apply suggestions from code review Co-authored-by: Robert Ing --- src/MixpanelEventForwarder.js | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/MixpanelEventForwarder.js b/src/MixpanelEventForwarder.js index 797a288..e1e5d9c 100644 --- a/src/MixpanelEventForwarder.js +++ b/src/MixpanelEventForwarder.js @@ -16,7 +16,7 @@ // ** Glossary of terms // Mixpanel Terms: // user_id: A unique identifier used by the Mixpanel.identify method to identify a unique user. This will map to what an mParticle customer selects in the UI, which translates to the forwarderSettings.userIdentificationType. -// device_id: A unique identifier used by Mixpanel to identify an anonymous user, usually a guid +// device_id: A unique identifier used by Mixpanel to identify an anonymous user, usually a guid. mParticle and Mixpnael generate their own device ids. // distinct_id: A unique identifier that Mixpanel uses to bridge a user and a device. Usually the // distinct_id has a prefix of $device:guid to denote an anonymouse user // and this will be replaced by the user_id once the user has been identified by @@ -189,31 +189,33 @@ var constructor = function () { } function onIdentifyComplete(user) { - // When mParticle identifies a user, the user might - // actually be anonymous. We only want to send an + // Mixpanel considers any user with an identity to be a known user. + // In mParticle, a user will always have an MPID even if they are anonymous. + // When mParticle identifies a user, because the user might + // actually be anonymous, we only want to send an // identify request to Mixpanel if the user is - // actually known. Only known (logged in) users - // will have userIdentities. + // actually known. If a user has any user identities, they are + // considered to be "known" users. var userIdentities = getUserIdentities(user); if (!isEmpty(userIdentities)) { sendIdentifyRequest(user, userIdentities); } else { - return 'User is anonymous'; + return 'Modified user does not have user identities and will not be sent to Mixpanel to Identify'; } } function onModifyComplete(user) { // Mixpanel does not have the concept of modifying a // user's identity. For the time being, we will rely on - // doing a simple Mixpanel.identify request. However + // doing a simple Mixpanel.identify request for backwards compatibility. However // this method may be deprecated in a future release var userIdentities = getUserIdentities(user); if (!isEmpty(userIdentities)) { sendIdentifyRequest(user, userIdentities); } else { - return 'User is anonymous'; + return 'Modified user does not have user identities and will not be sent to Mixpanel to Identify'; } } From c22a89163f31f246515cc1d3fc02e978ef6f543b Mon Sep 17 00:00:00 2001 From: Alexander Sapountzis Date: Mon, 30 Oct 2023 19:09:49 -0400 Subject: [PATCH 8/9] Address PR Comments --- test/src/tests.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test/src/tests.js b/test/src/tests.js index cf077d9..b538dd7 100644 --- a/test/src/tests.js +++ b/test/src/tests.js @@ -104,8 +104,8 @@ describe('Mixpanel Forwarder', function () { setCalledAttributes(data, 'identifyCalled'); }; - this.mparticle.reset = function (data) { - setCalledAttributes(data, 'resetCalled'); + this.mparticle.reset = function () { + setCalledAttributes(null, 'resetCalled'); }; this.mparticle.alias = function (data) { @@ -149,6 +149,10 @@ describe('Mixpanel Forwarder', function () { var API_HOST = 'https://api.mixpanel.com'; var identificationTypes = [ + { + userIdentificationType: 'MPID', + expectedProperty: 'mpid1', + }, { userIdentificationType: 'CustomerId', expectedProperty: 'cust1', From de2925bd54e46788f3d604604d340b61784ebaf2 Mon Sep 17 00:00:00 2001 From: Alex S <49695018+alexs-mparticle@users.noreply.github.com> Date: Mon, 30 Oct 2023 21:03:02 -0400 Subject: [PATCH 9/9] Update src/MixpanelEventForwarder.js Co-authored-by: Robert Ing --- src/MixpanelEventForwarder.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MixpanelEventForwarder.js b/src/MixpanelEventForwarder.js index e1e5d9c..73c8178 100644 --- a/src/MixpanelEventForwarder.js +++ b/src/MixpanelEventForwarder.js @@ -201,7 +201,7 @@ var constructor = function () { if (!isEmpty(userIdentities)) { sendIdentifyRequest(user, userIdentities); } else { - return 'Modified user does not have user identities and will not be sent to Mixpanel to Identify'; + return 'Identified user does not have user identities and will not be sent to Mixpanel to Identify'; } }