Merge pull request #2089 from overleaf/em-mailchimp-unsubscribe

Handle error on Mailchimp unsubscribe when deleting users

GitOrigin-RevId: 8923480e6d50de45003fd7741610f995753a412b
This commit is contained in:
Eric Mc Sween
2019-09-03 15:25:01 +00:00
committed by sharelatex
parent 3791b8d288
commit 869fcf7952
19 changed files with 780 additions and 591 deletions
@@ -1,119 +1,114 @@
/* eslint-disable
camelcase,
handle-callback-err,
max-len,
no-unused-vars,
*/
// TODO: This file was created by bulk-decaffeinate.
// Fix any style issues and re-enable lint.
/*
* decaffeinate suggestions:
* DS102: Remove unnecessary code created because of implicit returns
* DS207: Consider shorter variations of null checks
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
let UserController
const UserHandler = require('./UserHandler')
const UserDeleter = require('./UserDeleter')
const UserGetter = require('./UserGetter')
const { User } = require('../../models/User')
const newsLetterManager = require('../Newsletter/NewsletterManager')
const NewsletterManager = require('../Newsletter/NewsletterManager')
const UserRegistrationHandler = require('./UserRegistrationHandler')
const logger = require('logger-sharelatex')
const metrics = require('metrics-sharelatex')
const Url = require('url')
const AuthenticationManager = require('../Authentication/AuthenticationManager')
const AuthenticationController = require('../Authentication/AuthenticationController')
const UserSessionsManager = require('./UserSessionsManager')
const UserUpdater = require('./UserUpdater')
const SudoModeHandler = require('../SudoMode/SudoModeHandler')
const settings = require('settings-sharelatex')
const Errors = require('../Errors/Errors')
const OError = require('@overleaf/o-error')
const HttpErrors = require('@overleaf/o-error/http')
const EmailHandler = require('../Email/EmailHandler')
module.exports = UserController = {
const UserController = {
tryDeleteUser(req, res, next) {
const user_id = AuthenticationController.getLoggedInUserId(req)
const userId = AuthenticationController.getLoggedInUserId(req)
const { password } = req.body
logger.log({ user_id }, 'trying to delete user account')
logger.log({ userId }, 'trying to delete user account')
if (password == null || password === '') {
logger.err(
{ user_id },
{ userId },
'no password supplied for attempt to delete account'
)
return res.sendStatus(403)
}
AuthenticationManager.authenticate({ _id: user_id }, password, function(
err,
user
) {
if (err != null) {
logger.warn(
{ user_id },
'error authenticating during attempt to delete account'
)
return next(err)
}
if (!user) {
logger.err({ user_id }, 'auth failed during attempt to delete account')
return res.sendStatus(403)
}
UserDeleter.deleteUser(
user_id,
{ deleterUser: user, ipAddress: req.ip },
function(err) {
if (err) {
let errorData = {
message: 'error while deleting user account',
info: { user_id }
}
if (err instanceof Errors.SubscriptionAdminDeletionError) {
// set info.public.error for JSON response so frontend can display
// a specific message
errorData.info.public = {
error: 'SubscriptionAdminDeletionError'
}
return next(
new HttpErrors.UnprocessableEntityError(errorData).withCause(
err
)
)
} else {
return next(new OError(errorData).withCause(err))
}
}
const sessionId = req.sessionID
if (typeof req.logout === 'function') {
req.logout()
}
req.session.destroy(function(err) {
if (err != null) {
logger.warn({ err }, 'error destorying session')
return next(err)
}
UserSessionsManager.untrackSession(user, sessionId)
return res.sendStatus(200)
})
AuthenticationManager.authenticate(
{ _id: userId },
password,
(err, user) => {
if (err != null) {
logger.warn(
{ userId },
'error authenticating during attempt to delete account'
)
return next(err)
}
)
})
},
unsubscribe(req, res) {
const user_id = AuthenticationController.getLoggedInUserId(req)
return UserGetter.getUser(user_id, (err, user) =>
newsLetterManager.unsubscribe(user, () => res.send())
if (!user) {
logger.err({ userId }, 'auth failed during attempt to delete account')
return res.sendStatus(403)
}
UserDeleter.deleteUser(
userId,
{ deleterUser: user, ipAddress: req.ip },
err => {
if (err) {
let errorData = {
message: 'error while deleting user account',
info: { userId }
}
if (err instanceof Errors.SubscriptionAdminDeletionError) {
// set info.public.error for JSON response so frontend can display
// a specific message
errorData.info.public = {
error: 'SubscriptionAdminDeletionError'
}
return next(
new HttpErrors.UnprocessableEntityError(errorData).withCause(
err
)
)
} else {
return next(new OError(errorData).withCause(err))
}
}
const sessionId = req.sessionID
if (typeof req.logout === 'function') {
req.logout()
}
req.session.destroy(err => {
if (err != null) {
logger.warn({ err }, 'error destorying session')
return next(err)
}
UserSessionsManager.untrackSession(user, sessionId)
res.sendStatus(200)
})
}
)
}
)
},
unsubscribe(req, res, next) {
const userId = AuthenticationController.getLoggedInUserId(req)
UserGetter.getUser(userId, (err, user) => {
if (err != null) {
return next(err)
}
NewsletterManager.unsubscribe(user, err => {
if (err != null) {
logger.warn(
{ err, user },
'Failed to unsubscribe user from newsletter'
)
}
res.send()
})
})
},
updateUserSettings(req, res, next) {
const user_id = AuthenticationController.getLoggedInUserId(req)
logger.log({ user_id }, 'updating account settings')
return User.findById(user_id, function(err, user) {
const userId = AuthenticationController.getLoggedInUserId(req)
logger.log({ userId }, 'updating account settings')
User.findById(userId, (err, user) => {
if (err != null || user == null) {
logger.err({ err, user_id }, 'problem updaing user settings')
logger.err({ err, userId }, 'problem updaing user settings')
return res.sendStatus(500)
}
@@ -163,7 +158,10 @@ module.exports = UserController = {
user.ace.lineHeight = req.body.lineHeight
}
return user.save(function(err) {
user.save(err => {
if (err != null) {
return next(err)
}
const newEmail =
req.body.email != null
? req.body.email.trim().toLowerCase()
@@ -178,19 +176,17 @@ module.exports = UserController = {
first_name: user.first_name,
last_name: user.last_name
})
return res.sendStatus(200)
res.sendStatus(200)
} else if (newEmail.indexOf('@') === -1) {
// email invalid
return res.sendStatus(400)
res.sendStatus(400)
} else {
// update the user email
return UserUpdater.changeEmailAddress(user_id, newEmail, function(
err
) {
UserUpdater.changeEmailAddress(userId, newEmail, err => {
if (err) {
let errorData = {
message: 'problem updaing users email address',
info: { user_id, newEmail, public: {} }
info: { userId, newEmail, public: {} }
}
if (err instanceof Errors.EmailExistsError) {
errorData.info.public.message = req.i18n.translate(
@@ -208,10 +204,10 @@ module.exports = UserController = {
)
}
}
return User.findById(user_id, function(err, user) {
User.findById(userId, (err, user) => {
if (err != null) {
logger.err(
{ err, user_id },
{ err, userId },
'error getting user for email update'
)
return res.send(500)
@@ -221,12 +217,12 @@ module.exports = UserController = {
first_name: user.first_name,
last_name: user.last_name
})
return UserHandler.populateTeamInvites(user, function(err) {
UserHandler.populateTeamInvites(user, err => {
// need to refresh this in the background
if (err != null) {
logger.err({ err }, 'error populateTeamInvites')
}
return res.sendStatus(200)
res.sendStatus(200)
})
})
})
@@ -236,9 +232,6 @@ module.exports = UserController = {
},
_doLogout(req, cb) {
if (cb == null) {
cb = function(err) {}
}
metrics.inc('user.logout')
const user = AuthenticationController.getSessionUser(req)
logger.log({ user }, 'logging out')
@@ -246,26 +239,26 @@ module.exports = UserController = {
if (typeof req.logout === 'function') {
req.logout()
} // passport logout
return req.session.destroy(function(err) {
req.session.destroy(err => {
if (err) {
logger.warn({ err }, 'error destorying session')
cb(err)
return cb(err)
}
if (user != null) {
UserSessionsManager.untrackSession(user, sessionId)
SudoModeHandler.clearSudoMode(user._id)
}
return cb()
cb()
})
},
logout(req, res, next) {
return UserController._doLogout(req, function(err) {
UserController._doLogout(req, err => {
if (err != null) {
return next(err)
}
const redirect_url = '/login'
return res.redirect(redirect_url)
const redirectUrl = '/login'
res.redirect(redirectUrl)
})
},
@@ -291,21 +284,17 @@ module.exports = UserController = {
},
register(req, res, next) {
if (next == null) {
next = function(error) {}
}
const { email } = req.body
if (email == null || email === '') {
res.sendStatus(422) // Unprocessable Entity
return
return res.sendStatus(422) // Unprocessable Entity
}
return UserRegistrationHandler.registerNewUserAndSendActivationEmail(
UserRegistrationHandler.registerNewUserAndSendActivationEmail(
email,
function(error, user, setNewPasswordUrl) {
(error, user, setNewPasswordUrl) => {
if (error != null) {
return next(error)
}
return res.json({
res.json({
email: user.email,
setNewPasswordUrl
})
@@ -314,22 +303,15 @@ module.exports = UserController = {
},
clearSessions(req, res, next) {
if (next == null) {
next = function(error) {}
}
metrics.inc('user.clear-sessions')
const user = AuthenticationController.getSessionUser(req)
logger.log({ user_id: user._id }, 'clearing sessions for user')
return UserSessionsManager.revokeAllUserSessions(
user,
[req.sessionID],
function(err) {
if (err != null) {
return next(err)
}
return res.sendStatus(201)
logger.log({ userId: user._id }, 'clearing sessions for user')
UserSessionsManager.revokeAllUserSessions(user, [req.sessionID], err => {
if (err != null) {
return next(err)
}
)
res.sendStatus(201)
})
},
changePassword(req, res, next) {
@@ -337,9 +319,9 @@ module.exports = UserController = {
const internalError = {
message: { type: 'error', text: req.i18n.translate('internal_error') }
}
const user_id = AuthenticationController.getLoggedInUserId(req)
const userId = AuthenticationController.getLoggedInUserId(req)
AuthenticationManager.authenticate(
{ _id: user_id },
{ _id: userId },
req.body.currentPassword,
(err, user) => {
if (err) {
@@ -411,3 +393,5 @@ module.exports = UserController = {
)
}
}
module.exports = UserController