Skip to content

Commit 2174e54

Browse files
author
sachin-maheshwari
authored
Merge pull request #277 from rakibansary/feat/onboard-wizard
feat: onboarding checklist rule
2 parents 696519a + 1eb28e1 commit 2174e54

File tree

2 files changed

+104
-78
lines changed

2 files changed

+104
-78
lines changed

web-assets/auth0/dev-tenant/rules/onboardingChecklist.js

Lines changed: 52 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,45 @@
11
function (user, context, callback) {
22
if (context.clientID === configuration.CLIENT_ACCOUNTS_LOGIN) {
33
console.log("rule:onboarding-checklist:enter");
4+
console.log("rule:onboarding-checklist:context.request", context.request);
45

56
if (context.redirect) {
67
console.log("rule:onboarding-checklist:exiting due to context being a redirect");
78
return callback(null, user, context);
89
}
910

1011
const _ = require('lodash');
12+
const moment = require('moment');
1113

1214
let handle = _.get(user, "handle", null);
1315
const provider = _.get(user, "identities[0].provider", null);
1416
if (!handle && provider === "auth0") {
1517
handle = _.get(user, "nickname", null);
1618
}
1719

18-
let createdAt = _.get(user, "created_at", null);
19-
console.log('rule:onboarding-checklist: user created at', createdAt);
20+
console.log("rule:onboarding-checklist: fetch onboarding_checklist for email/handle: ", user.email, handle, provider);
21+
22+
const createdAt = _.get(user, "created_at", null);
23+
const thresholdDate = moment(configuration.PROFILE_CREATION_DATE_THRESHOLD, "YYYY-MM-DD");
24+
25+
try {
26+
// For users created before thresholdDate, we don't want to check onboarding_checklist
27+
// This is because older profiles might not have onboarding_checklist data and they don't need to see the onboarding_wizard
28+
if (createdAt && !thresholdDate.isBefore(moment(createdAt))) {
29+
console.log("rule:onboarding-checklist: user created before threshold date. Not checking onboarding_checklist.");
30+
return callback(null, user, context);
31+
}
32+
} catch (err) {
33+
console.log("rule:onboarding-checklist: failed to compare userCreationDate", createdAt, " with threshold. Error", err);
34+
}
2035

36+
/**
37+
* Returns M2M token needed to fetch onboarding_checklist
38+
*/
2139
const getToken = function(callback) {
2240
if (global.M2MToken) {
2341
console.log('rule:onboarding-checklist:M2M token is available');
24-
const jwt = require('jsonwebtoken');
25-
const moment = require('moment');
42+
const jwt = require('jsonwebtoken');
2643
const decoded = jwt.decode(global.M2MToken);
2744
const exp = moment.unix(decoded.exp);
2845

@@ -59,39 +76,37 @@ function (user, context, callback) {
5976
console.log('rule:onboarding-checklist:failed to fetch M2M token.');
6077
return callback(null, user, context);
6178
}
62-
63-
console.log("rule:onboarding-checklist: fetch onboarding_checklist for email/handle: ", user.email, handle, provider);
6479
global.AUTH0_CLAIM_NAMESPACE = "https://" + configuration.DOMAIN + "/";
65-
try {
66-
const axios = require('axios@0.19.2');
80+
const axios = require('axios@0.19.2');
81+
82+
const options = {
83+
method: 'GET',
84+
url: `https://api.${configuration.DOMAIN}/v5/members/${handle}/traits?traitIds=onboarding_checklist`,
85+
headers: {
86+
Authorization: `Bearer ${token}`
87+
}
88+
};
6789

68-
const redirectUrl = `https://platform.${configuration.DOMAIN}/onboard`;
69-
const options = {
70-
method: 'GET',
71-
url: `https://api.${configuration.DOMAIN}/v5/members/${handle}/traits?traitIds=onboarding_checklist`,
72-
headers: {
73-
Authorization: `Bearer ${token}`
74-
}
75-
};
76-
77-
axios(options).then(result => {
78-
const data = result.data;
90+
// Fetch onboarding_checklist using v5 member Api.
91+
axios(options)
92+
.then(result => {
93+
try {
94+
const data = result.data;
7995

80-
if (data.length === 0) {
81-
context.redirect = {
82-
url: redirectUrl
83-
};
84-
console.log('rule:onboarding-checklist:Setting redirectUrl', redirectUrl);
96+
if (data.length === 0) {
97+
// User doesn't have any traits with traitId onboarding_checklist and should be shown the onboarding wizard
98+
user.show_onboarding_wizard = true;
99+
console.log('rule:onboarding-checklist:Setting show_onboarding_wizard to true', user);
85100
return callback(null, user, context);
86101
}
87102

88103
const onboardingChecklistTrait = data.filter((item) => item.traitId === 'onboarding_checklist')[0].traits;
89104

90105
for (let checklistTrait of onboardingChecklistTrait.data) {
91106
if (
92-
checklistTrait.onboarding_wizard !== null &&
93-
(checklistTrait.onboarding_wizard.status !== null ||
94-
checklistTrait.onboarding_wizard.skip)
107+
checklistTrait.onboarding_wizard != null &&
108+
(checklistTrait.onboarding_wizard.status != null || // any valid status indicates user has already seen onboarding wizard and needn't be shown again.
109+
checklistTrait.onboarding_wizard.skip) // for certain signup routes skip is set to true, and thus onboarding wizard needn't be shown
95110
) {
96111
return callback(null, user, context);
97112
}
@@ -110,21 +125,19 @@ function (user, context, callback) {
110125
}
111126
}
112127
}
113-
114-
context.redirect = {
115-
url: redirectUrl
116-
};
117-
console.log('rule:onboarding-checklist:Setting redirectUrl', redirectUrl);
128+
129+
// All checks failed - indicating user newly registered and needs to be shown the onboarding wizard
130+
console.log('rule:onboarding-checklist: set show_onboarding_wizard', user);
131+
user.show_onboarding_wizard = true;
118132
return callback(null, user, context);
119-
}).catch(requestError => {
120-
console.log("rule:onboarding-checklist:Failed fetching onboarding_checklist with error", requestError.response.status);
133+
} catch (e) {
134+
console.log("rule:onboarding-checklist:Error in fetching onboarding_checklist", e);
121135
return callback(null, user, context);
122-
});
123-
124-
} catch (e) {
125-
console.log("rule:onboarding-checklist:Error in fetching onboarding_checklist", + e);
136+
}
137+
}).catch(requestError => {
138+
console.log("rule:onboarding-checklist:Failed fetching onboarding_checklist with error", requestError.response.status);
126139
return callback(null, user, context);
127-
}
140+
});
128141
});
129142
} else {
130143
return callback(null, user, context);

web-assets/js/setupAuth0WithRedirect.js

Lines changed: 52 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ const authSetup = function () {
4444
const mode = qs['mode'] || 'signIn';
4545
let returnAppUrl = handleSpecificReturnUrl(qs['retUrl'], 'retUrl');
4646
let appUrl = qs['appUrl'] || false;
47+
let onboardingWizardUrl = null;
4748

4849
if (utmSource &&
4950
(utmSource != 'undefined') &&
@@ -229,6 +230,12 @@ const authSetup = function () {
229230
return token ? !isTokenExpired(token) : false;
230231
};
231232

233+
const redirectToOnboardingWizard = function () {
234+
logger("redirect to onboarding wizard");
235+
const hostname = window.location.host.replace('www.', '');
236+
window.location = `https://platform.${hostname}/onboard`;
237+
}
238+
232239
const redirectToApp = function () {
233240
logger("redirect to app", appUrl);
234241
if (appUrl) {
@@ -256,53 +263,59 @@ const authSetup = function () {
256263
}
257264

258265
const storeToken = function () {
259-
auth0.getIdTokenClaims().then(function (claims) {
260-
idToken = claims.__raw;
261-
let userActive = false;
262-
Object.keys(claims).findIndex(function (key) {
263-
if (key.includes('active')) {
264-
userActive = claims[key];
265-
return true;
266-
}
267-
return false;
268-
});
269-
if (userActive) {
270-
let tcsso = '';
266+
auth0.getUser().then(function (user) {
267+
auth0.getIdTokenClaims().then(function (claims) {
268+
idToken = claims.__raw;
269+
let userActive = false;
271270
Object.keys(claims).findIndex(function (key) {
272-
if (key.includes(tcSSOCookie)) {
273-
tcsso = claims[key];
271+
if (key.includes('active')) {
272+
userActive = claims[key];
274273
return true;
275274
}
276275
return false;
277276
});
278-
logger('Storing token...', true);
279-
try {
280-
const exT = getCookieExpiry(idToken);
281-
if (exT) {
282-
setDomainCookie(tcJWTCookie, idToken, exT);
283-
setDomainCookie(v3JWTCookie, idToken, exT);
284-
setDomainCookie(tcSSOCookie, tcsso, exT);
285-
} else {
286-
setCookie(tcJWTCookie, idToken, cookieExpireIn);
287-
setCookie(v3JWTCookie, idToken, cookieExpireIn);
288-
setCookie(tcSSOCookie, tcsso, cookieExpireIn);
277+
if (userActive) {
278+
let tcsso = '';
279+
Object.keys(claims).findIndex(function (key) {
280+
if (key.includes(tcSSOCookie)) {
281+
tcsso = claims[key];
282+
return true;
283+
}
284+
return false;
285+
});
286+
logger('Storing token...', true);
287+
try {
288+
const exT = getCookieExpiry(idToken);
289+
if (exT) {
290+
setDomainCookie(tcJWTCookie, idToken, exT);
291+
setDomainCookie(v3JWTCookie, idToken, exT);
292+
setDomainCookie(tcSSOCookie, tcsso, exT);
293+
} else {
294+
setCookie(tcJWTCookie, idToken, cookieExpireIn);
295+
setCookie(v3JWTCookie, idToken, cookieExpireIn);
296+
setCookie(tcSSOCookie, tcsso, cookieExpireIn);
297+
}
298+
} catch (e) {
299+
logger('Error occured in fecthing token expiry time', e.message);
289300
}
290-
} catch (e) {
291-
logger('Error occured in fecthing token expiry time', e.message);
292-
}
293301

294-
// session still active, but app calling login
295-
if (!appUrl && returnAppUrl) {
296-
appUrl = returnAppUrl
302+
if (user.show_onboarding_wizard) {
303+
redirectToOnboardingWizard();
304+
} else {
305+
// session still active, but app calling login
306+
if (!appUrl && returnAppUrl) {
307+
appUrl = returnAppUrl
308+
}
309+
redirectToApp();
310+
}
311+
} else {
312+
logger("User active ? ", userActive);
313+
host = registerSuccessUrl;
314+
logout();
297315
}
298-
redirectToApp();
299-
} else {
300-
logger("User active ? ", userActive);
301-
host = registerSuccessUrl;
302-
logout();
303-
}
304-
}).catch(function (e) {
305-
logger("Error in fetching token from auth0: ", e);
316+
}).catch(function (e) {
317+
logger("Error in fetching token from auth0: ", e);
318+
});
306319
});
307320
};
308321

0 commit comments

Comments
 (0)