mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-29 06:03:42 -05:00
Merge pull request #17530 from overleaf/dp-teardown-onboarding-flow-split-test
Teardown onboarding flow split test GitOrigin-RevId: 48e95e4e736772074cb68d195fc950a9da3aebcf
This commit is contained in:
parent
2f74b79d3a
commit
b1928cecef
12 changed files with 168 additions and 26 deletions
|
@ -7,7 +7,6 @@ const fs = require('fs')
|
|||
const ErrorController = require('../Errors/ErrorController')
|
||||
const SessionManager = require('../Authentication/SessionManager')
|
||||
|
||||
const SplitTestHandler = require('../SplitTests/SplitTestHandler')
|
||||
const { expressify } = require('@overleaf/promise-utils')
|
||||
const logger = require('@overleaf/logger')
|
||||
|
||||
|
@ -32,17 +31,11 @@ async function index(req, res) {
|
|||
|
||||
async function home(req, res) {
|
||||
if (Features.hasFeature('homepage') && homepageExists) {
|
||||
const onboardingFlowAssignment =
|
||||
await SplitTestHandler.promises.getAssignment(req, res, 'onboarding-flow')
|
||||
AnalyticsManager.recordEventForSession(req.session, 'home-page-view', {
|
||||
page: req.path,
|
||||
})
|
||||
|
||||
res.render('external/home/website-redesign/index', {
|
||||
onboardingFlowVariant: onboardingFlowAssignment.variant,
|
||||
hideNewsletterCheckbox:
|
||||
onboardingFlowAssignment.variant === 'token-confirmation-odc',
|
||||
})
|
||||
res.render('external/home/website-redesign/index')
|
||||
} else {
|
||||
res.redirect('/login')
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ const UserDeleter = require('./UserDeleter')
|
|||
const UserGetter = require('./UserGetter')
|
||||
const UserUpdater = require('./UserUpdater')
|
||||
const Analytics = require('../Analytics/AnalyticsManager')
|
||||
const SplitTestHandler = require('../SplitTests/SplitTestHandler')
|
||||
const UserOnboardingEmailManager = require('./UserOnboardingEmailManager')
|
||||
const UserPostRegistrationAnalyticsManager = require('./UserPostRegistrationAnalyticsManager')
|
||||
const OError = require('@overleaf/o-error')
|
||||
|
@ -37,16 +36,9 @@ async function _addAffiliation(user, affiliationOptions) {
|
|||
}
|
||||
|
||||
async function recordRegistrationEvent(user) {
|
||||
const onboardingFlowAssignment =
|
||||
await SplitTestHandler.promises.getAssignmentForUser(
|
||||
user._id,
|
||||
'onboarding-flow'
|
||||
)
|
||||
|
||||
try {
|
||||
const segmentation = {
|
||||
'home-registration': 'default',
|
||||
'onboarding-flow': onboardingFlowAssignment.variant,
|
||||
}
|
||||
if (user.thirdPartyIdentifiers && user.thirdPartyIdentifiers.length > 0) {
|
||||
segmentation.provider = user.thirdPartyIdentifiers[0].providerId
|
||||
|
|
|
@ -945,7 +945,6 @@
|
|||
"new_tag": "Nyt tag",
|
||||
"new_tag_name": "Navn til nyt tag",
|
||||
"newsletter": "Nyhedsbrev",
|
||||
"newsletter-accept": "Jeg vil gerne modtage e-mails om produkttilbud, virksomhedsnyheder og begivenheder.",
|
||||
"newsletter_info_note": "Du vil stadig modtage vigtige e-mails såsom projektinvitationer og sikkerhedsbeskeder (nulstilling af kode, kontoforbindelser, osv.).",
|
||||
"newsletter_info_subscribed": "Du er <0>tilmeldt</0> til __appName__s nyhedsbrev. Hvis du foretrækker ikke at modtage disse e-mails, kan du altid framelde dig.",
|
||||
"newsletter_info_summary": "Hvert par måneder sender vi et nyhedsbrev som opsummerer de nyeste tilgængelige funktioner.",
|
||||
|
|
|
@ -937,7 +937,6 @@
|
|||
"new_snippet_project": "Ohne Titel",
|
||||
"new_subscription_will_be_billed_immediately": "Dein neues Abonnement wird umgehend mit deiner aktuellen Zahlungsmethode abgerechnet.",
|
||||
"newsletter": "Newsletter",
|
||||
"newsletter-accept": "Ich möchte E-Mails zu Produktangeboten, Neuigkeiten und Veranstaltungen des Unternehmens erhalten.",
|
||||
"newsletter_info_note": "Bitte beachte: Du erhältst weiterhin wichtige E-Mails wie Projekteinladungen und Sicherheitsbenachrichtigungen (Passwortzurücksetzung, Kontoverknüpfung usw.).",
|
||||
"newsletter_info_subscribed": "Du hast den __appName__-Newsletter <0>abonniert</0>. Wenn du diese E-Mails lieber nicht erhalten möchtest, kannst du dich jederzeit abmelden.",
|
||||
"newsletter_info_summary": "Alle paar Monate versenden wir einen Newsletter mit einer Zusammenfassung der neu verfügbaren Funktionen.",
|
||||
|
|
|
@ -1177,7 +1177,6 @@
|
|||
"new_tag": "New Tag",
|
||||
"new_tag_name": "New tag name",
|
||||
"newsletter": "Newsletter",
|
||||
"newsletter-accept": "I’d like emails about product offers and company news and events.",
|
||||
"newsletter_info_note": "Please note: you will still receive important emails, such as project invites and security notifications (password resets, account linking, etc).",
|
||||
"newsletter_info_subscribed": "You are currently <0>subscribed</0> to the __appName__ newsletter. If you would prefer not to receive this email then you can unsubscribe at any time.",
|
||||
"newsletter_info_summary": "Every few months we send a newsletter out summarizing the new features available.",
|
||||
|
|
|
@ -606,7 +606,6 @@
|
|||
"new_password": "Nouveau mot de passe",
|
||||
"new_project": "Nouveau projet",
|
||||
"new_snippet_project": "Sans titre",
|
||||
"newsletter-accept": "Je souhaite recevoir des courriels portant sur des offres de produits et sur les actualités et événements de notre entreprise.",
|
||||
"next_payment_of_x_collectected_on_y": "Le prochain paiement de <0>__paymentAmmount__</0> sera débité le <1>__collectionDate__</1>.",
|
||||
"nl": "Hollandais",
|
||||
"no": "Norvégien",
|
||||
|
|
|
@ -413,7 +413,6 @@
|
|||
"new_name": "Novo Nome",
|
||||
"new_password": "Nova Senha",
|
||||
"new_project": "Novo Projeto",
|
||||
"newsletter-accept": "Gostaria de receber e-mails sobre ofertas de produtos, notícias e eventos da empresa.",
|
||||
"next_payment_of_x_collectected_on_y": "O próximo pagamento de <0>__paymentAmmount__</0> será coletado em <1>__collectionDate__</1>",
|
||||
"nl": "Holandês",
|
||||
"no": "Noroeguês",
|
||||
|
|
|
@ -579,7 +579,6 @@
|
|||
"new_password": "Nytt lösenord",
|
||||
"new_project": "Nytt projekt",
|
||||
"new_snippet_project": "Namnlös",
|
||||
"newsletter-accept": "Jag vill få e-post om produkterbjudanden, nyheter och evenemang från företaget.",
|
||||
"next_payment_of_x_collectected_on_y": "Nästa betalning på <0>__paymentAmmount__</0> kommer att genomföras den <1>__collectionDate__</1>",
|
||||
"nl": "Holländska",
|
||||
"no": "Norska",
|
||||
|
|
|
@ -1153,7 +1153,6 @@
|
|||
"new_tag": "新建标签",
|
||||
"new_tag_name": "新标签名",
|
||||
"newsletter": "电子邮件",
|
||||
"newsletter-accept": "我想要关于产品报价和公司新闻和事件的电子邮件。",
|
||||
"newsletter_info_note": "请注意:您仍然会收到重要的电子邮件,例如项目邀请和安全通知(密码重置、帐户链接等)。",
|
||||
"newsletter_info_subscribed": "您当前<0>订阅了</0>__appName__ 新闻资讯。 如果您不想收到此电子邮件,则可以随时取消订阅。",
|
||||
"newsletter_info_summary": "每隔几个月,我们就会发送一份简讯,总结可用的新功能。",
|
||||
|
|
|
@ -8,6 +8,50 @@ const MockReCAPTCHAApi = require('../mocks/MockReCaptchaApi')
|
|||
const {
|
||||
gracefulShutdown,
|
||||
} = require('../../../../app/src/infrastructure/GracefulShutdown')
|
||||
const { app } = require('../../../../app/src/infrastructure/Server')
|
||||
|
||||
/**
|
||||
* Inject an endpoint to get the current users session into our app. This
|
||||
* endpoint should only be available when running in the test environment.
|
||||
* It is used to retrieve an email confirmation code when registering a
|
||||
* new user account in acceptance tests.
|
||||
*/
|
||||
const addSessionEndpoint = app => {
|
||||
const stack = app._router.stack
|
||||
|
||||
stack.forEach(layer => {
|
||||
if (layer.name !== 'router' || !layer.handle || !layer.handle.stack) {
|
||||
return
|
||||
}
|
||||
|
||||
// We want to position our /dev/session endpoint next to the /dev/csrf
|
||||
// endpoint so we check each router for the presence of this path.
|
||||
const newRouteIndex = layer.handle.stack.findIndex(
|
||||
route =>
|
||||
route &&
|
||||
route.route &&
|
||||
route.route.path &&
|
||||
route.route.path === '/dev/csrf'
|
||||
)
|
||||
|
||||
if (newRouteIndex !== -1) {
|
||||
// We add our new endpoint to the end of the router stack.
|
||||
layer.handle.get('/dev/session', (req, res) => {
|
||||
return res.json(req.session)
|
||||
})
|
||||
|
||||
const routeStack = layer.handle.stack
|
||||
const sessionRoute = routeStack[routeStack.length - 1]
|
||||
|
||||
// Then we reposition it next to the /dev/csrf endpoint.
|
||||
layer.handle.stack = [
|
||||
...routeStack.slice(0, newRouteIndex),
|
||||
sessionRoute,
|
||||
...routeStack.slice(newRouteIndex, routeStack.length - 1),
|
||||
]
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
logger.logger.level('error')
|
||||
|
||||
|
@ -18,6 +62,7 @@ MockReCAPTCHAApi.initialize(2222)
|
|||
let server
|
||||
|
||||
before('start main app', function (done) {
|
||||
addSessionEndpoint(app)
|
||||
server = App.listen(23000, 'localhost', done)
|
||||
})
|
||||
|
||||
|
|
|
@ -32,6 +32,46 @@ class User {
|
|||
})
|
||||
}
|
||||
|
||||
getSession(callback) {
|
||||
this.request.get(
|
||||
{
|
||||
url: '/dev/session',
|
||||
},
|
||||
(err, response, body) => {
|
||||
if (err != null) {
|
||||
return callback(err)
|
||||
}
|
||||
if (response.statusCode !== 200) {
|
||||
return callback(
|
||||
new Error(
|
||||
`get session failed: status=${
|
||||
response.statusCode
|
||||
} body=${JSON.stringify(body)}`
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
const session = JSON.parse(response.body)
|
||||
callback(null, session)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
getEmailConfirmationCode(callback) {
|
||||
this.getSession((err, session) => {
|
||||
if (err != null) {
|
||||
return callback(err)
|
||||
}
|
||||
|
||||
const code = session.pendingUserRegistration?.confirmCode
|
||||
if (!code) {
|
||||
return callback(new Error('No confirmation code found in session'))
|
||||
}
|
||||
|
||||
callback(null, code)
|
||||
})
|
||||
}
|
||||
|
||||
resetCookies() {
|
||||
this.jar = request.jar()
|
||||
this.request = request.defaults({
|
||||
|
@ -114,12 +154,40 @@ class User {
|
|||
)
|
||||
)
|
||||
}
|
||||
db.users.findOne({ email: this.email }, (error, user) => {
|
||||
|
||||
this.getEmailConfirmationCode((error, code) => {
|
||||
if (error != null) {
|
||||
return callback(error)
|
||||
}
|
||||
this.setExtraAttributes(user)
|
||||
callback(null, user)
|
||||
|
||||
this.request.post(
|
||||
{
|
||||
url: '/registration/confirm-email',
|
||||
json: { code },
|
||||
},
|
||||
(error, response, body) => {
|
||||
if (error != null) {
|
||||
return callback(error)
|
||||
}
|
||||
if (response.statusCode !== 200) {
|
||||
return callback(
|
||||
new Error(
|
||||
`email confirmation failed: status=${
|
||||
response.statusCode
|
||||
} body=${JSON.stringify(body)}`
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
db.users.findOne({ email: this.email }, (error, user) => {
|
||||
if (error != null) {
|
||||
return callback(error)
|
||||
}
|
||||
this.setExtraAttributes(user)
|
||||
callback(null, user)
|
||||
})
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
)
|
||||
|
|
|
@ -140,6 +140,33 @@ class UserHelper {
|
|||
this._csrfToken = body
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests user session
|
||||
*/
|
||||
async getSession() {
|
||||
const response = await this.fetch('/dev/session')
|
||||
const body = await response.text()
|
||||
|
||||
if (response.status !== 200) {
|
||||
throw new Error(
|
||||
`get session failed: status=${response.status} body=${JSON.stringify(
|
||||
body
|
||||
)}`
|
||||
)
|
||||
}
|
||||
return JSON.parse(body)
|
||||
}
|
||||
|
||||
async getEmailConfirmationCode() {
|
||||
const session = await this.getSession()
|
||||
|
||||
const code = session.pendingUserRegistration?.confirmCode
|
||||
if (!code) {
|
||||
throw new Error('No confirmation code found in session')
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
/**
|
||||
* Make request to POST /logout
|
||||
* @param {object} [options] options to pass to request
|
||||
|
@ -353,6 +380,30 @@ class UserHelper {
|
|||
`cannot register intitutional email: ${options.json.email}`
|
||||
)
|
||||
}
|
||||
|
||||
const code = await userHelper.getEmailConfirmationCode()
|
||||
|
||||
const confirmationResponse = await userHelper.fetch(
|
||||
'/registration/confirm-email',
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Accept: 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ code }),
|
||||
...options,
|
||||
}
|
||||
)
|
||||
|
||||
if (confirmationResponse.status !== 200) {
|
||||
throw new Error(
|
||||
`email confirmation failed: status=${
|
||||
response.status
|
||||
} body=${JSON.stringify(body)}`
|
||||
)
|
||||
}
|
||||
|
||||
userHelper.user = await UserGetter.promises.getUser({
|
||||
email: userData.email,
|
||||
})
|
||||
|
|
Loading…
Reference in a new issue