fleet/website/api/controllers/save-questionnaire-progress.js
Eric cb035d873d
Website: add psychologicalStage to User model (#18408)
Related to: https://github.com/fleetdm/confidential/issues/6155

Changes:
- Added a new attribute to the `User` model: `psychologicalStage`
- Updated `save-questionnaire-progress` to update a user's
`psychologicalStage` based on their current answers/progress on the
/start questionnaire
- Updated the personalization on the /contact page to use the
`psychologicalStage` from the user model
- Updated the value of a unselectable form option on the /start page
2024-04-18 21:18:36 -05:00

156 lines
7 KiB
JavaScript
Vendored

module.exports = {
friendlyName: 'Save questionnaire progress and continue',
description: 'Saves the user\'s current progress in the get started questionnaire',
inputs: {
currentStep: {
type: 'string',
description: 'The step of the get started questionnaire that is being saved.',
isIn: [
'start',
'what-are-you-using-fleet-for',
'have-you-ever-used-fleet',
'how-many-hosts',
'will-you-be-self-hosting',
'what-are-you-working-on-eo-security',
'what-does-your-team-manage-eo-it',
'what-does-your-team-manage-vm',
'what-do-you-manage-mdm',
'is-it-any-good',
'what-did-you-think',
'deploy-fleet-in-your-environment',
'managed-cloud-for-growing-deployments',
'self-hosted-deploy',
]
},
formData: {
type: {},
description: 'The formdata that will be saved for this step of the get started questionnaire'
},
},
exits: {
success: {
outputDescription: 'All get started questionnaire answers accumulated so far by this user.',
outputType: {}
},
},
fn: async function ({currentStep, formData}) {
// find this user's DB record.
let userRecord = this.req.me;
let questionnaireProgress;
// If this user doesn't have a lastSubmittedGetStartedQuestionnaireStep or getStartedQuestionnaireAnswers, create an empty dictionary to store their answers.
if(!userRecord.lastSubmittedGetStartedQuestionnaireStep || _.isEmpty(userRecord.getStartedQuestionnaireAnswers)) {
questionnaireProgress = {};
} else {// other wise clone it from the user record.
questionnaireProgress = _.clone(userRecord.getStartedQuestionnaireAnswers);
}
// When the 'what-are-you-using-fleet-for' is completed, update this user's DB record and session to include their answer.
if(currentStep === 'what-are-you-using-fleet-for') {
let primaryBuyingSituation = formData.primaryBuyingSituation;
await User.updateOne({id: this.req.me.id})
.set({
primaryBuyingSituation
});
// Send a POST request to Zapier
await sails.helpers.http.post.with({
url: 'https://hooks.zapier.com/hooks/catch/3627242/3pl7yt1/',
data: {
primaryBuyingSituation,
emailAddress: this.req.me.emailAddress,
webhookSecret: sails.config.custom.zapierSandboxWebhookSecret,
}
})
.timeout(5000)
.tolerate(['non200Response', 'requestFailed'], (err)=>{
// Note that Zapier responds with a 2xx status code even if something goes wrong, so just because this message is not logged doesn't mean everything is hunky dory. More info: https://github.com/fleetdm/fleet/pull/6380#issuecomment-1204395762
sails.log.warn(`When a user completed the 'What are you using Fleet for' questionnaire step, a lead/contact could not be updated in the CRM for this email address: ${this.req.me.emailAddress}. Raw error: ${err}`);
return;
});
// Set the primary buying situation in the user's session.
this.req.session.primaryBuyingSituation = primaryBuyingSituation;
}
// ┌─┐┌─┐┌┬┐ ┌─┐┌─┐┬ ┬┌─┐┬ ┬┌─┐┬ ┌─┐┌─┐┬┌─┐┌─┐┬ ┌─┐┌┬┐┌─┐┌─┐┌─┐
// └─┐├┤ │ ├─┘└─┐└┬┘│ ├─┤│ ││ │ ││ ┬││ ├─┤│ └─┐ │ ├─┤│ ┬├┤
// └─┘└─┘ ┴ ┴ └─┘ ┴ └─┘┴ ┴└─┘┴─┘└─┘└─┘┴└─┘┴ ┴┴─┘ └─┘ ┴ ┴ ┴└─┘└─┘
// This is how the questionnaire steps/options change a user's psychologicalStage value.
// 'start': No change
// 'what-are-you-using-fleet-for': No change
// 'have-you-ever-used-fleet':
// - yes-deployed: » Stage 6
// - yes-recently-deployed: » Stage 6
// - yes-deployed-local: » Stage 3 (Tried Fleet but don't have a use case)
// - yes-deployed-long-time: No change
// - no: No change
// 'how-many-hosts': No change
// 'will-you-be-self-hosting': No change
// 'what-are-you-working-on-eo-security'
// - no-use-case-yet: » No change
// - All other options » Stage 4
// 'what-does-your-team-manage-eo-it'
// - no-use-case-yet: » No change
// - All other options » Stage 4
// 'what-does-your-team-manage-vm'
// - no-use-case-yet: » No change
// - All other options » Stage 4
// 'what-do-you-manage-mdm'
// - no-use-case-yet: » No change
// - All other options » Stage 4
// 'is-it-any-good': No change
// 'what-did-you-think'
// - deploy-fleet-in-environment » Stage 5
// - let-me-think-about-it » No change
// - host-fleet-for-me » N/A (currently not selectable, but should set the user's psychologicalStage to stage 5)
let psychologicalStage = userRecord.psychologicalStage;
// Get the value of the submitted formData, we do this so we only need to check one variable, instead of (formData.attribute === 'foo');
let valueFromFormData = _.values(formData)[0];
if(currentStep === 'have-you-ever-used-fleet') {
if(['yes-deployed', 'yes-recently-deployed'].includes(valueFromFormData)) {
// If the user has Fleet deployed, set their stage to 6.
psychologicalStage = '6 - Has team buy-in';
} else if(valueFromFormData === 'yes-deployed-local'){
// If they've tried Fleet locally, set their stage to 3.
psychologicalStage = '3 - Intrigued';
}
} else if(['what-are-you-working-on-eo-security','what-does-your-team-manage-eo-it','what-does-your-team-manage-vm','what-do-you-manage-mdm'].includes(currentStep)){
if(valueFromFormData === 'no-use-case-yet') {
// If this user doe not have a use case for Fleet yet, set their psyStage to 3
psychologicalStage = '3 - Intrigued';
} else {// Otherwise, they have a use case and will be set to stage 4.
psychologicalStage = '4 - Has use case';
}
} else if(currentStep === 'what-did-you-think') {
// If the user is ready to deploy Fleet in their work environemnt, then they're ready to get buy-in from their team, so set their psyStage to 5.
if(valueFromFormData === 'deploy-fleet-in-environment') {
psychologicalStage = '5 - Personally confident';
}
// If the user selects let me think about it, their stage will not change.
}//fi
// Set the user's answer to the current step.
questionnaireProgress[currentStep] = formData;
// Clone the questionnaireProgress to prevent any mutations from sending it through the updateOne Waterline method.
let getStartedProgress = _.clone(questionnaireProgress);
// Update the user's database model.
await User.updateOne({id: userRecord.id})
.set({
getStartedQuestionnaireAnswers: questionnaireProgress,
lastSubmittedGetStartedQuestionnaireStep: currentStep,
psychologicalStage
});
// Return the JSON dictionary of form data submitted by this user.
return getStartedProgress;
}
};