Merge pull request #18320 from overleaf/dp-add-secondary-prompt-ui

Add secondary email form V2 (with Captcha this time)

GitOrigin-RevId: b06216a2c9cb5b3b09305a17992eca506a0047f5
This commit is contained in:
David
2024-05-27 10:22:40 +00:00
committed by Copybot
parent 5aea030184
commit 635aae7b1f
22 changed files with 837 additions and 59 deletions
@@ -17,7 +17,9 @@ const AnalyticsManager = require('../Analytics/AnalyticsManager')
const UserPrimaryEmailCheckHandler = require('../User/UserPrimaryEmailCheckHandler')
const UserAuditLogHandler = require('./UserAuditLogHandler')
const { RateLimiter } = require('../../infrastructure/RateLimiter')
const Features = require('../../infrastructure/Features')
const tsscmp = require('tsscmp')
const Modules = require('../../infrastructure/Modules')
const AUDIT_LOG_TOKEN_PREFIX_LENGTH = 10
@@ -208,9 +210,7 @@ async function addWithConfirmationCode(req, res) {
confirmCodeExpiresTimestamp,
}
return res.json({
redir: '/user/emails/confirm-secondary',
})
return res.sendStatus(200)
} catch (err) {
if (err.name === 'EmailExistsError') {
return res.status(409).json({
@@ -418,6 +418,45 @@ async function resendSecondaryEmailConfirmationCode(req, res) {
}
}
async function confirmSecondaryEmailPage(req, res) {
const userId = SessionManager.getLoggedInUserId(req.session)
if (!req.session.pendingSecondaryEmail) {
const redirectURL =
AuthenticationController.getRedirectFromSession(req) || '/project'
return res.redirect(redirectURL)
}
AnalyticsManager.recordEventForUser(
userId,
'confirm-secondary-email-page-displayed'
)
res.render('user/confirmSecondaryEmail', {
email: req.session.pendingSecondaryEmail.email,
})
}
async function addSecondaryEmailPage(req, res) {
const userId = SessionManager.getLoggedInUserId(req.session)
const confirmedEmails =
await UserGetter.promises.getUserConfirmedEmails(userId)
if (confirmedEmails.length >= 2) {
const redirectURL =
AuthenticationController.getRedirectFromSession(req) || '/project'
return res.redirect(redirectURL)
}
AnalyticsManager.recordEventForUser(
userId,
'add-secondary-email-page-displayed'
)
res.render('user/addSecondaryEmail')
}
async function primaryEmailCheckPage(req, res) {
const userId = SessionManager.getLoggedInUserId(req.session)
const user = await UserGetter.promises.getUser(userId, {
@@ -443,10 +482,35 @@ async function primaryEmailCheck(req, res) {
await UserUpdater.promises.updateUser(userId, {
$set: { lastPrimaryEmailCheck: new Date() },
})
AnalyticsManager.recordEventForUserInBackground(
userId,
'primary-email-check-done'
)
// We want to redirect to prompt a user to add a secondary email if their primary
// is an institutional email and they dont' already have a secondary.
if (Features.hasFeature('saas') && req.capabilitySet.has('add-affiliation')) {
const confirmedEmails =
await UserGetter.promises.getUserConfirmedEmails(userId)
if (confirmedEmails.length < 2) {
const { email: primaryEmail } = SessionManager.getSessionUser(req.session)
const primaryEmailDomain = EmailHelper.getDomain(primaryEmail)
const institution = (
await Modules.promises.hooks.fire(
'getInstitutionViaDomain',
primaryEmailDomain
)
)?.[0]
if (institution) {
return AsyncFormHelper.redirect(req, res, '/user/emails/add-secondary')
}
}
}
AsyncFormHelper.redirect(req, res, '/project')
}
@@ -558,6 +622,10 @@ const UserEmailsController = {
sendReconfirmation,
addSecondaryEmailPage: expressify(addSecondaryEmailPage),
confirmSecondaryEmailPage: expressify(confirmSecondaryEmailPage),
primaryEmailCheckPage: expressify(primaryEmailCheckPage),
primaryEmailCheck: expressify(primaryEmailCheck),
@@ -79,6 +79,18 @@ async function getUserFullEmails(userId) {
)
}
async function getUserConfirmedEmails(userId) {
const user = await UserGetter.promises.getUser(userId, {
emails: 1,
})
if (!user) {
throw new Error('User not Found')
}
return user.emails.filter(email => !!email.confirmedAt)
}
async function getSsoUsersAtInstitution(institutionId, projection) {
if (!projection) {
throw new Error('missing projection')
@@ -124,6 +136,8 @@ const UserGetter = {
getUserFullEmails: callbackify(getUserFullEmails),
getUserConfirmedEmails: callbackify(getUserConfirmedEmails),
getUserByMainEmail(email, projection, callback) {
email = email.trim()
if (arguments.length === 2) {
+9 -15
View File
@@ -336,6 +336,7 @@ function initialize(webRouter, privateApiRouter, publicApiRouter) {
webRouter.post(
'/user/emails/primary-email-check',
AuthenticationController.requireLogin(),
PermissionsController.useCapabilities(),
UserEmailsController.primaryEmailCheck
)
@@ -348,6 +349,7 @@ function initialize(webRouter, privateApiRouter, publicApiRouter) {
CaptchaMiddleware.validateCaptcha('addEmail'),
UserEmailsController.add
)
webRouter.post(
'/user/emails/delete',
AuthenticationController.requireLogin(),
@@ -366,29 +368,21 @@ function initialize(webRouter, privateApiRouter, publicApiRouter) {
RateLimiterMiddleware.rateLimit(rateLimiters.endorseEmail),
UserEmailsController.endorse
)
}
webRouter.post(
'/user/emails/secondary',
if (Features.hasFeature('saas')) {
webRouter.get(
'/user/emails/add-secondary',
AuthenticationController.requireLogin(),
PermissionsController.requirePermission('add-secondary-email'),
RateLimiterMiddleware.rateLimit(rateLimiters.addEmail),
UserEmailsController.addWithConfirmationCode
UserEmailsController.addSecondaryEmailPage
)
webRouter.post(
webRouter.get(
'/user/emails/confirm-secondary',
AuthenticationController.requireLogin(),
PermissionsController.requirePermission('add-secondary-email'),
RateLimiterMiddleware.rateLimit(rateLimiters.checkEmailConfirmationCode),
UserEmailsController.checkSecondaryEmailConfirmationCode
)
webRouter.post(
'/user/emails/resend-secondary-confirmation',
AuthenticationController.requireLogin(),
PermissionsController.requirePermission('add-secondary-email'),
RateLimiterMiddleware.rateLimit(rateLimiters.resendConfirmationCode),
UserEmailsController.resendSecondaryEmailConfirmationCode
UserEmailsController.confirmSecondaryEmailPage
)
}