From 9d7a2a1c24c68fd3b64235605b1420b40dc635e0 Mon Sep 17 00:00:00 2001 From: Sabe Jones Date: Mon, 27 Jul 2015 14:25:11 -0500 Subject: [PATCH 1/4] feat(analytics): Party properties Adds tracking of the user's party ID and size as user-level analytics properties. --- test/spec/services/analyticsServicesSpec.js | 5 ++++- website/public/js/controllers/groupsCtrl.js | 14 ++++++++++---- website/public/js/services/analyticsServices.js | 1 + website/public/js/services/groupServices.js | 4 ++++ website/public/js/services/questServices.js | 6 ++++-- 5 files changed, 23 insertions(+), 7 deletions(-) diff --git a/test/spec/services/analyticsServicesSpec.js b/test/spec/services/analyticsServicesSpec.js index 2ee414d953..55071b5679 100644 --- a/test/spec/services/analyticsServicesSpec.js +++ b/test/spec/services/analyticsServicesSpec.js @@ -9,6 +9,7 @@ describe('Analytics Service', function () { user = specHelper.newUser(); user.contributor = {}; user.purchased = { plan: {} }; + user.flags.tour = { intro: null }; module(function($provide) { $provide.value('User', {user: user}); @@ -217,7 +218,8 @@ describe('Analytics Service', function () { Level: 24, Mana: 41, contributorLevel: 1, - subscription: 'unique-plan-id' + subscription: 'unique-plan-id', + tutorialComplete: true }; beforeEach(function() { @@ -230,6 +232,7 @@ describe('Analytics Service', function () { user.stats.mp = 41; user.contributor.level = 1; user.purchased.plan.planId = 'unique-plan-id'; + user.flags.tour.intro = -2; analytics.updateUser(); clock.tick(); diff --git a/website/public/js/controllers/groupsCtrl.js b/website/public/js/controllers/groupsCtrl.js index 564bb1878b..6908ca1d70 100644 --- a/website/public/js/controllers/groupsCtrl.js +++ b/website/public/js/controllers/groupsCtrl.js @@ -266,6 +266,9 @@ habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Shared', 'Groups', ' } $scope.message.content = ''; $scope._sending = false; + if (group.type == 'party') { + Analytics.updateUser({'partySize':group.memberCount}); + } if (group.privacy == 'public'){ Analytics.track({'hitType':'event','eventCategory':'behavior','eventAction':'group chat','groupType':group.type,'privacy':group.privacy,'groupName':group.name,'message':message}); } else { @@ -475,17 +478,19 @@ habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Shared', 'Groups', ' $scope.create = function(group){ group.$save(function(){ Analytics.track({'hitType':'event','eventCategory':'behavior','eventAction':'join group','owner':true,'groupType':'party','privacy':'private'}); + Analytics.updateUser({'partyID':group.id,'partySize':1}); $rootScope.hardRedirect('/#/options/groups/party'); }); - } + }; $scope.join = function(party){ var group = new Groups.Group({_id: party.id, name: party.name}); group.$join(function(){ Analytics.track({'hitType':'event','eventCategory':'behavior','eventAction':'join group','owner':false,'groupType':'party','privacy':'private'}); + Analytics.updateUser({'partyID':party.id}); $rootScope.hardRedirect('/#/options/groups/party'); }); - } + }; // TODO: refactor guild and party leave into one function $scope.leave = function(keep) { @@ -494,10 +499,11 @@ habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Shared', 'Groups', ' $scope.popoverEl.popover('destroy'); } else { Groups.Group.leave({gid: $scope.selectedGroup._id, keep:keep}, undefined, function(){ + Analytics.updateUser({'partySize':null,'partyID':null}); $rootScope.hardRedirect('/#/options/groups/party'); }); } - } + }; // TODO: refactor guild and party clickLeave into one function $scope.clickLeave = function(group, $event){ @@ -547,7 +553,7 @@ habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Shared', 'Groups', ' $scope.questAccept = function(party){ Groups.questAccept(party); - } + }; $scope.questReject = function(party){ Groups.questReject(party); diff --git a/website/public/js/services/analyticsServices.js b/website/public/js/services/analyticsServices.js index cc238aeb84..a7016df866 100644 --- a/website/public/js/services/analyticsServices.js +++ b/website/public/js/services/analyticsServices.js @@ -107,6 +107,7 @@ properties.Level = user.stats.lvl; properties.Mana = Math.floor(user.stats.mp); } + if (user.flags.tour && user.flags.tour.intro === '-2') properties.tutorialComplete = true; if (user.contributor && user.contributor.level) properties.contributorLevel = user.contributor.level; if (user.purchased && user.purchased.plan.planId) properties.subscription = user.purchased.plan.planId; } diff --git a/website/public/js/services/groupServices.js b/website/public/js/services/groupServices.js index 6235cb9f5a..fc31b706f0 100644 --- a/website/public/js/services/groupServices.js +++ b/website/public/js/services/groupServices.js @@ -64,21 +64,25 @@ function($rootScope, ApiUrl, $resource, $q, $http, User, Challenges, Analytics, }, questAccept: function(party){ + Analytics.updateUser({'partySize':party.memberCount,'partyID':party.id}); party.$questAccept() .then(syncUser, logError); }, questReject: function(party){ + Analytics.updateUser({'partySize':party.memberCount,'partyID':party.id}); party.$questReject() .then(syncUser, logError); }, questCancel: function(party){ + Analytics.updateUser({'partySize':party.memberCount,'partyID':party.id}); party.$questCancel() .then(syncUser, logError); }, questAbort: function(party){ + Analytics.updateUser({'partySize':party.memberCount,'partyID':party.id}); party.$questAbort() .then(syncUser, logError); }, diff --git a/website/public/js/services/questServices.js b/website/public/js/services/questServices.js index d65f5e4043..7e7252a0d0 100644 --- a/website/public/js/services/questServices.js +++ b/website/public/js/services/questServices.js @@ -16,6 +16,7 @@ function questsFactory($rootScope,Content,Groups,User,Analytics) { var user = User.user; + var party = $rootScope.party; function lockQuest(quest,ignoreLevel) { if (!ignoreLevel){ @@ -86,8 +87,9 @@ function questInit(){ Analytics.track({'hitType':'event','eventCategory':'behavior','eventAction':'quest','owner':true,'response':'accept','questName':$rootScope.selectedQuest.key}); - $rootScope.party.$questAccept({key:$rootScope.selectedQuest.key}, function(){ - $rootScope.party.$get(); + Analytics.updateUser({'partySize':party.memberCount,'partyID':party.id}); + party.$questAccept({key:$rootScope.selectedQuest.key}, function(){ + party.$get(); $rootScope.$state.go('options.social.party'); }); closeQuest(); From e9ed561907eee5fb6df2947519ed243db8931c35 Mon Sep 17 00:00:00 2001 From: Sabe Jones Date: Mon, 27 Jul 2015 14:34:31 -0500 Subject: [PATCH 2/4] fix(analytics): Add missing ID update Also make the order of partyID and partySize consistent across updateUser calls. --- website/public/js/controllers/groupsCtrl.js | 2 +- website/public/js/services/groupServices.js | 8 ++++---- website/public/js/services/questServices.js | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/website/public/js/controllers/groupsCtrl.js b/website/public/js/controllers/groupsCtrl.js index 6908ca1d70..52bd43cf39 100644 --- a/website/public/js/controllers/groupsCtrl.js +++ b/website/public/js/controllers/groupsCtrl.js @@ -267,7 +267,7 @@ habitrpg.controller("GroupsCtrl", ['$scope', '$rootScope', 'Shared', 'Groups', ' $scope.message.content = ''; $scope._sending = false; if (group.type == 'party') { - Analytics.updateUser({'partySize':group.memberCount}); + Analytics.updateUser({'partyID':group.id,'partySize':group.memberCount}); } if (group.privacy == 'public'){ Analytics.track({'hitType':'event','eventCategory':'behavior','eventAction':'group chat','groupType':group.type,'privacy':group.privacy,'groupName':group.name,'message':message}); diff --git a/website/public/js/services/groupServices.js b/website/public/js/services/groupServices.js index fc31b706f0..c75474ea5f 100644 --- a/website/public/js/services/groupServices.js +++ b/website/public/js/services/groupServices.js @@ -64,25 +64,25 @@ function($rootScope, ApiUrl, $resource, $q, $http, User, Challenges, Analytics, }, questAccept: function(party){ - Analytics.updateUser({'partySize':party.memberCount,'partyID':party.id}); + Analytics.updateUser({'partyID':party.id,'partySize':party.memberCount}); party.$questAccept() .then(syncUser, logError); }, questReject: function(party){ - Analytics.updateUser({'partySize':party.memberCount,'partyID':party.id}); + Analytics.updateUser({'partyID':party.id,'partySize':party.memberCount}); party.$questReject() .then(syncUser, logError); }, questCancel: function(party){ - Analytics.updateUser({'partySize':party.memberCount,'partyID':party.id}); + Analytics.updateUser({'partyID':party.id,'partySize':party.memberCount}); party.$questCancel() .then(syncUser, logError); }, questAbort: function(party){ - Analytics.updateUser({'partySize':party.memberCount,'partyID':party.id}); + Analytics.updateUser({'partyID':party.id,'partySize':party.memberCount}); party.$questAbort() .then(syncUser, logError); }, diff --git a/website/public/js/services/questServices.js b/website/public/js/services/questServices.js index 7e7252a0d0..9483837d7b 100644 --- a/website/public/js/services/questServices.js +++ b/website/public/js/services/questServices.js @@ -87,7 +87,7 @@ function questInit(){ Analytics.track({'hitType':'event','eventCategory':'behavior','eventAction':'quest','owner':true,'response':'accept','questName':$rootScope.selectedQuest.key}); - Analytics.updateUser({'partySize':party.memberCount,'partyID':party.id}); + Analytics.updateUser({'partyID':party.id,'partySize':party.memberCount}); party.$questAccept({key:$rootScope.selectedQuest.key}, function(){ party.$get(); $rootScope.$state.go('options.social.party'); From f6bbae3bebe165409d311c3002e4c7891ff70756 Mon Sep 17 00:00:00 2001 From: Sabe Jones Date: Mon, 27 Jul 2015 15:13:59 -0500 Subject: [PATCH 3/4] fix(analytics): Bad comparison Corrects an error caught via test, where the check for intro tour completion would always fail. Also tweaks the updateUser behavior to save an explicit false if tour completion data is not found, including a test for that behavior. --- test/spec/services/analyticsServicesSpec.js | 2 ++ test/spec/services/groupServicesSpec.js | 2 +- website/public/js/services/analyticsServices.js | 3 ++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/test/spec/services/analyticsServicesSpec.js b/test/spec/services/analyticsServicesSpec.js index 55071b5679..ca726e37ec 100644 --- a/test/spec/services/analyticsServicesSpec.js +++ b/test/spec/services/analyticsServicesSpec.js @@ -183,6 +183,7 @@ describe('Analytics Service', function () { expectedProperties.Health = 48; expectedProperties.Level = 24; expectedProperties.Mana = 41; + expectedProperties.tutorialComplete = false; beforeEach(function() { user._id = 'unique-user-id'; @@ -192,6 +193,7 @@ describe('Analytics Service', function () { user.stats.hp = 47.8; user.stats.lvl = 24; user.stats.mp = 41; + user.flags.tour.intro = 3; analytics.updateUser(properties); clock.tick(); diff --git a/test/spec/services/groupServicesSpec.js b/test/spec/services/groupServicesSpec.js index f0bfb3a538..0a4534c0c6 100644 --- a/test/spec/services/groupServicesSpec.js +++ b/test/spec/services/groupServicesSpec.js @@ -5,7 +5,7 @@ describe('groupServices', function() { beforeEach(function() { module(function($provide) { - $provide.value('User', {}); + $provide.value('User', {user:user}); }); inject(function(_$httpBackend_, Groups, User) { diff --git a/website/public/js/services/analyticsServices.js b/website/public/js/services/analyticsServices.js index a7016df866..244aec529a 100644 --- a/website/public/js/services/analyticsServices.js +++ b/website/public/js/services/analyticsServices.js @@ -107,7 +107,8 @@ properties.Level = user.stats.lvl; properties.Mana = Math.floor(user.stats.mp); } - if (user.flags.tour && user.flags.tour.intro === '-2') properties.tutorialComplete = true; + if (user.flags && user.flags.tour && user.flags.tour.intro === -2) {properties.tutorialComplete = true} + else {properties.tutorialComplete = false}; if (user.contributor && user.contributor.level) properties.contributorLevel = user.contributor.level; if (user.purchased && user.purchased.plan.planId) properties.subscription = user.purchased.plan.planId; } From 7c56f5e7f6bcee3151bf538a17e52b7587863782 Mon Sep 17 00:00:00 2001 From: Sabe Jones Date: Tue, 28 Jul 2015 13:26:39 -0500 Subject: [PATCH 4/4] fix(analytics): Tweaks per code review --- test/server_side/analytics.test.js | 6 ++++-- website/public/js/services/analyticsServices.js | 3 +-- website/src/analytics.js | 2 ++ 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/test/server_side/analytics.test.js b/test/server_side/analytics.test.js index 2c421f9dab..059414be23 100644 --- a/test/server_side/analytics.test.js +++ b/test/server_side/analytics.test.js @@ -221,7 +221,8 @@ describe('analytics', function() { var user = { stats: stats, contributor: { level: 1 }, - purchased: { plan: { planId: 'foo-plan' } } + purchased: { plan: { planId: 'foo-plan' } }, + flags: {tour: {intro: -2}} }; analyticsData.user = user; @@ -246,7 +247,8 @@ describe('analytics', function() { Level: 4, Mana: 30, contributorLevel: 1, - subscription: 'foo-plan' + subscription: 'foo-plan', + tutorialComplete: true } }); }); diff --git a/website/public/js/services/analyticsServices.js b/website/public/js/services/analyticsServices.js index 244aec529a..135e7a205d 100644 --- a/website/public/js/services/analyticsServices.js +++ b/website/public/js/services/analyticsServices.js @@ -107,8 +107,7 @@ properties.Level = user.stats.lvl; properties.Mana = Math.floor(user.stats.mp); } - if (user.flags && user.flags.tour && user.flags.tour.intro === -2) {properties.tutorialComplete = true} - else {properties.tutorialComplete = false}; + properties.tutorialComplete = user.flags && user.flags.tour && user.flags.tour.intro === -2; if (user.contributor && user.contributor.level) properties.contributorLevel = user.contributor.level; if (user.purchased && user.purchased.plan.planId) properties.subscription = user.purchased.plan.planId; } diff --git a/website/src/analytics.js b/website/src/analytics.js index ecae3768d5..ad35adb9e7 100644 --- a/website/src/analytics.js +++ b/website/src/analytics.js @@ -152,6 +152,8 @@ function _formatUserData(user) { properties.Mana = Math.floor(user.stats.mp); } + properties.tutorialComplete = user.flags && user.flags.tour && user.flags.tour.intro === -2; + if (user.contributor && user.contributor.level) { properties.contributorLevel = user.contributor.level; }