mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Merge pull request #2163 from overleaf/ta-decaf-cleanup-user
Complete Decafeinate of User Feature GitOrigin-RevId: b8d7ebc59c4f6673392b4a0f33fb11e002d5a3a0
This commit is contained in:
parent
2031115f48
commit
c1c1b85a40
8 changed files with 200 additions and 405 deletions
|
@ -1,18 +1,3 @@
|
|||
/* 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 UserEmailsConfirmationHandler
|
||||
const EmailHelper = require('../Helpers/EmailHelper')
|
||||
const EmailHandler = require('../Email/EmailHandler')
|
||||
const OneTimeTokenHandler = require('../Security/OneTimeTokenHandler')
|
||||
|
@ -24,11 +9,8 @@ const UserGetter = require('./UserGetter')
|
|||
|
||||
const ONE_YEAR_IN_S = 365 * 24 * 60 * 60
|
||||
|
||||
module.exports = UserEmailsConfirmationHandler = {
|
||||
sendConfirmationEmail(user_id, email, emailTemplate, callback) {
|
||||
if (callback == null) {
|
||||
callback = function(error) {}
|
||||
}
|
||||
const UserEmailsConfirmationHandler = {
|
||||
sendConfirmationEmail(userId, email, emailTemplate, callback) {
|
||||
if (arguments.length === 3) {
|
||||
callback = emailTemplate
|
||||
emailTemplate = 'confirmEmail'
|
||||
|
@ -41,16 +23,16 @@ module.exports = UserEmailsConfirmationHandler = {
|
|||
}
|
||||
|
||||
email = EmailHelper.parseEmail(email)
|
||||
if (email == null) {
|
||||
if (!email) {
|
||||
return callback(new Error('invalid email'))
|
||||
}
|
||||
const data = { user_id, email }
|
||||
return OneTimeTokenHandler.getNewToken(
|
||||
const data = { user_id: userId, email }
|
||||
OneTimeTokenHandler.getNewToken(
|
||||
'email_confirmation',
|
||||
data,
|
||||
{ expiresIn: ONE_YEAR_IN_S },
|
||||
function(err, token) {
|
||||
if (err != null) {
|
||||
if (err) {
|
||||
return callback(err)
|
||||
}
|
||||
const emailOptions = {
|
||||
|
@ -58,49 +40,49 @@ module.exports = UserEmailsConfirmationHandler = {
|
|||
confirmEmailUrl: `${
|
||||
settings.siteUrl
|
||||
}/user/emails/confirm?token=${token}`,
|
||||
sendingUser_id: user_id
|
||||
sendingUser_id: userId
|
||||
}
|
||||
return EmailHandler.sendEmail(emailTemplate, emailOptions, callback)
|
||||
EmailHandler.sendEmail(emailTemplate, emailOptions, callback)
|
||||
}
|
||||
)
|
||||
},
|
||||
|
||||
confirmEmailFromToken(token, callback) {
|
||||
if (callback == null) {
|
||||
callback = function(error) {}
|
||||
}
|
||||
logger.log(
|
||||
{ token_start: token.slice(0, 8) },
|
||||
'confirming email from token'
|
||||
)
|
||||
return OneTimeTokenHandler.getValueFromTokenAndExpire(
|
||||
OneTimeTokenHandler.getValueFromTokenAndExpire(
|
||||
'email_confirmation',
|
||||
token,
|
||||
function(error, data) {
|
||||
if (error != null) {
|
||||
if (error) {
|
||||
return callback(error)
|
||||
}
|
||||
if (data == null) {
|
||||
if (!data) {
|
||||
return callback(new Errors.NotFoundError('no token found'))
|
||||
}
|
||||
const { user_id, email } = data
|
||||
const userId = data.user_id
|
||||
const email = data.email
|
||||
logger.log(
|
||||
{ data, user_id, email, token_start: token.slice(0, 8) },
|
||||
{ data, userId, email, token_start: token.slice(0, 8) },
|
||||
'found data for email confirmation'
|
||||
)
|
||||
if (user_id == null || email !== EmailHelper.parseEmail(email)) {
|
||||
if (!userId || email !== EmailHelper.parseEmail(email)) {
|
||||
return callback(new Errors.NotFoundError('invalid data'))
|
||||
}
|
||||
return UserGetter.getUser(user_id, {}, function(error, user) {
|
||||
if (error != null) {
|
||||
UserGetter.getUser(userId, {}, function(error, user) {
|
||||
if (error) {
|
||||
return callback(error)
|
||||
}
|
||||
if (!(user != null ? user._id : undefined)) {
|
||||
if (!user) {
|
||||
return callback(new Errors.NotFoundError('user not found'))
|
||||
}
|
||||
return UserUpdater.confirmEmail(user_id, email, callback)
|
||||
UserUpdater.confirmEmail(userId, email, callback)
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = UserEmailsConfirmationHandler
|
||||
|
|
|
@ -1,16 +1,3 @@
|
|||
/* eslint-disable
|
||||
handle-callback-err,
|
||||
max-len,
|
||||
*/
|
||||
// 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
|
||||
* DS103: Rewrite code to no longer use __guard__
|
||||
* DS207: Consider shorter variations of null checks
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
let UserEmailsController
|
||||
const AuthenticationController = require('../Authentication/AuthenticationController')
|
||||
const UserGetter = require('./UserGetter')
|
||||
|
@ -25,18 +12,18 @@ const HttpErrors = require('@overleaf/o-error/http')
|
|||
module.exports = UserEmailsController = {
|
||||
list(req, res, next) {
|
||||
const userId = AuthenticationController.getLoggedInUserId(req)
|
||||
return UserGetter.getUserFullEmails(userId, function(error, fullEmails) {
|
||||
if (error != null) {
|
||||
UserGetter.getUserFullEmails(userId, function(error, fullEmails) {
|
||||
if (error) {
|
||||
return next(error)
|
||||
}
|
||||
return res.json(fullEmails)
|
||||
res.json(fullEmails)
|
||||
})
|
||||
},
|
||||
|
||||
add(req, res, next) {
|
||||
const userId = AuthenticationController.getLoggedInUserId(req)
|
||||
const email = EmailHelper.parseEmail(req.body.email)
|
||||
if (email == null) {
|
||||
if (!email) {
|
||||
return res.sendStatus(422)
|
||||
}
|
||||
|
||||
|
@ -45,47 +32,44 @@ module.exports = UserEmailsController = {
|
|||
role: req.body.role,
|
||||
department: req.body.department
|
||||
}
|
||||
return UserUpdater.addEmailAddress(
|
||||
userId,
|
||||
email,
|
||||
affiliationOptions,
|
||||
function(error) {
|
||||
if (error != null) {
|
||||
return UserEmailsController._handleEmailError(error, req, res, next)
|
||||
}
|
||||
return UserEmailsConfirmationHandler.sendConfirmationEmail(
|
||||
userId,
|
||||
email,
|
||||
function(err) {
|
||||
if (error != null) {
|
||||
return next(error)
|
||||
}
|
||||
return res.sendStatus(204)
|
||||
}
|
||||
)
|
||||
UserUpdater.addEmailAddress(userId, email, affiliationOptions, function(
|
||||
error
|
||||
) {
|
||||
if (error) {
|
||||
return UserEmailsController._handleEmailError(error, req, res, next)
|
||||
}
|
||||
)
|
||||
UserEmailsConfirmationHandler.sendConfirmationEmail(
|
||||
userId,
|
||||
email,
|
||||
function(error) {
|
||||
if (error) {
|
||||
return next(error)
|
||||
}
|
||||
res.sendStatus(204)
|
||||
}
|
||||
)
|
||||
})
|
||||
},
|
||||
|
||||
remove(req, res, next) {
|
||||
const userId = AuthenticationController.getLoggedInUserId(req)
|
||||
const email = EmailHelper.parseEmail(req.body.email)
|
||||
if (email == null) {
|
||||
if (!email) {
|
||||
return res.sendStatus(422)
|
||||
}
|
||||
|
||||
return UserUpdater.removeEmailAddress(userId, email, function(error) {
|
||||
if (error != null) {
|
||||
UserUpdater.removeEmailAddress(userId, email, function(error) {
|
||||
if (error) {
|
||||
return next(error)
|
||||
}
|
||||
return res.sendStatus(200)
|
||||
res.sendStatus(200)
|
||||
})
|
||||
},
|
||||
|
||||
setDefault(req, res, next) {
|
||||
const userId = AuthenticationController.getLoggedInUserId(req)
|
||||
const email = EmailHelper.parseEmail(req.body.email)
|
||||
if (email == null) {
|
||||
if (!email) {
|
||||
return res.sendStatus(422)
|
||||
}
|
||||
UserUpdater.setDefaultEmailAddress(userId, email, err => {
|
||||
|
@ -100,20 +84,20 @@ module.exports = UserEmailsController = {
|
|||
endorse(req, res, next) {
|
||||
const userId = AuthenticationController.getLoggedInUserId(req)
|
||||
const email = EmailHelper.parseEmail(req.body.email)
|
||||
if (email == null) {
|
||||
if (!email) {
|
||||
return res.sendStatus(422)
|
||||
}
|
||||
|
||||
return endorseAffiliation(
|
||||
endorseAffiliation(
|
||||
userId,
|
||||
email,
|
||||
req.body.role,
|
||||
req.body.department,
|
||||
function(error) {
|
||||
if (error != null) {
|
||||
if (error) {
|
||||
return next(error)
|
||||
}
|
||||
return res.sendStatus(204)
|
||||
res.sendStatus(204)
|
||||
}
|
||||
)
|
||||
},
|
||||
|
@ -121,43 +105,36 @@ module.exports = UserEmailsController = {
|
|||
resendConfirmation(req, res, next) {
|
||||
const userId = AuthenticationController.getLoggedInUserId(req)
|
||||
const email = EmailHelper.parseEmail(req.body.email)
|
||||
if (email == null) {
|
||||
if (!email) {
|
||||
return res.sendStatus(422)
|
||||
}
|
||||
return UserGetter.getUserByAnyEmail(email, { _id: 1 }, function(
|
||||
error,
|
||||
user
|
||||
) {
|
||||
if (error != null) {
|
||||
UserGetter.getUserByAnyEmail(email, { _id: 1 }, function(error, user) {
|
||||
if (error) {
|
||||
return next(error)
|
||||
}
|
||||
if (
|
||||
user == null ||
|
||||
__guard__(user != null ? user._id : undefined, x => x.toString()) !==
|
||||
userId
|
||||
) {
|
||||
if (!user || user._id.toString() !== userId) {
|
||||
logger.log(
|
||||
{ userId, email, foundUserId: user != null ? user._id : undefined },
|
||||
{ userId, email, foundUserId: user && user._id },
|
||||
"email doesn't match logged in user"
|
||||
)
|
||||
return res.sendStatus(422)
|
||||
}
|
||||
logger.log({ userId, email }, 'resending email confirmation token')
|
||||
return UserEmailsConfirmationHandler.sendConfirmationEmail(
|
||||
UserEmailsConfirmationHandler.sendConfirmationEmail(
|
||||
userId,
|
||||
email,
|
||||
function(error) {
|
||||
if (error != null) {
|
||||
if (error) {
|
||||
return next(error)
|
||||
}
|
||||
return res.sendStatus(200)
|
||||
res.sendStatus(200)
|
||||
}
|
||||
)
|
||||
})
|
||||
},
|
||||
|
||||
showConfirm(req, res, next) {
|
||||
return res.render('user/confirm_email', {
|
||||
res.render('user/confirm_email', {
|
||||
token: req.query.token,
|
||||
title: 'confirm_email'
|
||||
})
|
||||
|
@ -165,23 +142,21 @@ module.exports = UserEmailsController = {
|
|||
|
||||
confirm(req, res, next) {
|
||||
const { token } = req.body
|
||||
if (token == null) {
|
||||
if (!token) {
|
||||
return res.sendStatus(422)
|
||||
}
|
||||
return UserEmailsConfirmationHandler.confirmEmailFromToken(token, function(
|
||||
error
|
||||
) {
|
||||
if (error != null) {
|
||||
UserEmailsConfirmationHandler.confirmEmailFromToken(token, function(error) {
|
||||
if (error) {
|
||||
if (error instanceof Errors.NotFoundError) {
|
||||
return res.status(404).json({
|
||||
res.status(404).json({
|
||||
message:
|
||||
'Sorry, your confirmation token is invalid or has expired. Please request a new email confirmation link.'
|
||||
})
|
||||
} else {
|
||||
return next(error)
|
||||
next(error)
|
||||
}
|
||||
} else {
|
||||
return res.sendStatus(200)
|
||||
res.sendStatus(200)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
@ -207,8 +182,3 @@ module.exports = UserEmailsController = {
|
|||
next(new HttpErrors.InternalServerError().withCause(error))
|
||||
}
|
||||
}
|
||||
function __guard__(value, transform) {
|
||||
return typeof value !== 'undefined' && value !== null
|
||||
? transform(value)
|
||||
: undefined
|
||||
}
|
||||
|
|
|
@ -1,16 +1,3 @@
|
|||
/* eslint-disable
|
||||
camelcase,
|
||||
handle-callback-err,
|
||||
max-len,
|
||||
*/
|
||||
// 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
|
||||
*/
|
||||
const mongojs = require('../../infrastructure/mongojs')
|
||||
const metrics = require('metrics-sharelatex')
|
||||
const logger = require('logger-sharelatex')
|
||||
|
@ -23,10 +10,7 @@ const Features = require('../../infrastructure/Features')
|
|||
|
||||
const UserGetter = {
|
||||
getUser(query, projection, callback) {
|
||||
if (callback == null) {
|
||||
callback = function(error, user) {}
|
||||
}
|
||||
if (query == null) {
|
||||
if (!query) {
|
||||
return callback(new Error('no query provided'))
|
||||
}
|
||||
if (arguments.length === 2) {
|
||||
|
@ -43,24 +27,18 @@ const UserGetter = {
|
|||
query = { _id: query }
|
||||
}
|
||||
|
||||
return db.users.findOne(query, projection, callback)
|
||||
db.users.findOne(query, projection, callback)
|
||||
},
|
||||
|
||||
getUserEmail(userId, callback) {
|
||||
if (callback == null) {
|
||||
callback = function(error, email) {}
|
||||
}
|
||||
return this.getUser(userId, { email: 1 }, (error, user) =>
|
||||
callback(error, user != null ? user.email : undefined)
|
||||
this.getUser(userId, { email: 1 }, (error, user) =>
|
||||
callback(error, user && user.email)
|
||||
)
|
||||
},
|
||||
|
||||
getUserFullEmails(userId, callback) {
|
||||
if (callback == null) {
|
||||
callback = function(error, emails) {}
|
||||
}
|
||||
return this.getUser(userId, { email: 1, emails: 1 }, function(error, user) {
|
||||
if (error != null) {
|
||||
this.getUser(userId, { email: 1, emails: 1 }, function(error, user) {
|
||||
if (error) {
|
||||
return callback(error)
|
||||
}
|
||||
if (!user) {
|
||||
|
@ -71,11 +49,11 @@ const UserGetter = {
|
|||
return callback(null, decorateFullEmails(user.email, user.emails, []))
|
||||
}
|
||||
|
||||
return getUserAffiliations(userId, function(error, affiliationsData) {
|
||||
if (error != null) {
|
||||
getUserAffiliations(userId, function(error, affiliationsData) {
|
||||
if (error) {
|
||||
return callback(error)
|
||||
}
|
||||
return callback(
|
||||
callback(
|
||||
null,
|
||||
decorateFullEmails(user.email, user.emails || [], affiliationsData)
|
||||
)
|
||||
|
@ -84,21 +62,15 @@ const UserGetter = {
|
|||
},
|
||||
|
||||
getUserByMainEmail(email, projection, callback) {
|
||||
if (callback == null) {
|
||||
callback = function(error, user) {}
|
||||
}
|
||||
email = email.trim()
|
||||
if (arguments.length === 2) {
|
||||
callback = projection
|
||||
projection = {}
|
||||
}
|
||||
return db.users.findOne({ email }, projection, callback)
|
||||
db.users.findOne({ email }, projection, callback)
|
||||
},
|
||||
|
||||
getUserByAnyEmail(email, projection, callback) {
|
||||
if (callback == null) {
|
||||
callback = function(error, user) {}
|
||||
}
|
||||
email = email.trim()
|
||||
if (arguments.length === 2) {
|
||||
callback = projection
|
||||
|
@ -106,21 +78,18 @@ const UserGetter = {
|
|||
}
|
||||
// $exists: true MUST be set to use the partial index
|
||||
const query = { emails: { $exists: true }, 'emails.email': email }
|
||||
return db.users.findOne(query, projection, (error, user) => {
|
||||
if (error != null || user != null) {
|
||||
db.users.findOne(query, projection, (error, user) => {
|
||||
if (error || user) {
|
||||
return callback(error, user)
|
||||
}
|
||||
|
||||
// While multiple emails are being rolled out, check for the main email as
|
||||
// well
|
||||
return this.getUserByMainEmail(email, projection, callback)
|
||||
this.getUserByMainEmail(email, projection, callback)
|
||||
})
|
||||
},
|
||||
|
||||
getUsersByAnyConfirmedEmail(emails, projection, callback) {
|
||||
if (callback == null) {
|
||||
callback = function(error, user) {}
|
||||
}
|
||||
if (arguments.length === 2) {
|
||||
callback = projection
|
||||
projection = {}
|
||||
|
@ -132,29 +101,19 @@ const UserGetter = {
|
|||
$elemMatch: { email: { $in: emails }, confirmedAt: { $exists: true } }
|
||||
}
|
||||
}
|
||||
return db.users.find(query, projection, (error, users) => {
|
||||
return callback(error, users)
|
||||
})
|
||||
db.users.find(query, projection, callback)
|
||||
},
|
||||
|
||||
getUsersByV1Ids(v1Ids, projection, callback) {
|
||||
if (callback == null) {
|
||||
callback = function(error, user) {}
|
||||
}
|
||||
if (arguments.length === 2) {
|
||||
callback = projection
|
||||
projection = {}
|
||||
}
|
||||
const query = { 'overleaf.id': { $in: v1Ids } }
|
||||
return db.users.find(query, projection, (error, users) => {
|
||||
return callback(error, users)
|
||||
})
|
||||
db.users.find(query, projection, callback)
|
||||
},
|
||||
|
||||
getUsersByHostname(hostname, projection, callback) {
|
||||
if (callback == null) {
|
||||
callback = function(error, users) {}
|
||||
}
|
||||
const reversedHostname = hostname
|
||||
.trim()
|
||||
.split('')
|
||||
|
@ -164,59 +123,49 @@ const UserGetter = {
|
|||
emails: { $exists: true },
|
||||
'emails.reversedHostname': reversedHostname
|
||||
}
|
||||
return db.users.find(query, projection, callback)
|
||||
db.users.find(query, projection, callback)
|
||||
},
|
||||
|
||||
getUsers(user_ids, projection, callback) {
|
||||
if (callback == null) {
|
||||
callback = function(error, users) {}
|
||||
}
|
||||
getUsers(userIds, projection, callback) {
|
||||
try {
|
||||
user_ids = user_ids.map(u => ObjectId(u.toString()))
|
||||
} catch (error1) {
|
||||
const error = error1
|
||||
userIds = userIds.map(u => ObjectId(u.toString()))
|
||||
} catch (error) {
|
||||
return callback(error)
|
||||
}
|
||||
|
||||
return db.users.find({ _id: { $in: user_ids } }, projection, callback)
|
||||
db.users.find({ _id: { $in: userIds } }, projection, callback)
|
||||
},
|
||||
|
||||
getUserOrUserStubById(user_id, projection, callback) {
|
||||
getUserOrUserStubById(userId, projection, callback) {
|
||||
let query
|
||||
if (callback == null) {
|
||||
callback = function(error, user, isStub) {}
|
||||
}
|
||||
try {
|
||||
query = { _id: ObjectId(user_id.toString()) }
|
||||
query = { _id: ObjectId(userId.toString()) }
|
||||
} catch (e) {
|
||||
return callback(new Error(e))
|
||||
}
|
||||
return db.users.findOne(query, projection, function(error, user) {
|
||||
if (error != null) {
|
||||
db.users.findOne(query, projection, function(error, user) {
|
||||
if (error) {
|
||||
return callback(error)
|
||||
}
|
||||
if (user != null) {
|
||||
if (user) {
|
||||
return callback(null, user, false)
|
||||
}
|
||||
return db.userstubs.findOne(query, projection, function(error, user) {
|
||||
if (error) {
|
||||
return callback(error)
|
||||
db.userstubs.findOne(query, projection, function(error, user) {
|
||||
if (error || user) {
|
||||
return callback(error, user)
|
||||
}
|
||||
if (user == null) {
|
||||
return callback()
|
||||
}
|
||||
return callback(null, user, true)
|
||||
callback(null, user, true)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
// check for duplicate email address. This is also enforced at the DB level
|
||||
ensureUniqueEmailAddress(newEmail, callback) {
|
||||
return this.getUserByAnyEmail(newEmail, function(error, user) {
|
||||
if (user != null) {
|
||||
this.getUserByAnyEmail(newEmail, function(error, user) {
|
||||
if (user) {
|
||||
return callback(new Errors.EmailExistsError())
|
||||
}
|
||||
return callback(error)
|
||||
callback(error)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -228,7 +177,7 @@ var decorateFullEmails = (defaultEmail, emailsData, affiliationsData) =>
|
|||
const affiliation = affiliationsData.find(
|
||||
aff => aff.email === emailData.email
|
||||
)
|
||||
if (affiliation != null) {
|
||||
if (affiliation) {
|
||||
const { institution, inferred, role, department } = affiliation
|
||||
emailData.affiliation = { institution, inferred, role, department }
|
||||
} else {
|
||||
|
|
|
@ -1,30 +1,15 @@
|
|||
/* eslint-disable
|
||||
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 UserHandler
|
||||
const TeamInvitesHandler = require('../Subscription/TeamInvitesHandler')
|
||||
|
||||
module.exports = UserHandler = {
|
||||
const UserHandler = {
|
||||
populateTeamInvites(user, callback) {
|
||||
return TeamInvitesHandler.createTeamInvitesForLegacyInvitedEmail(
|
||||
TeamInvitesHandler.createTeamInvitesForLegacyInvitedEmail(
|
||||
user.email,
|
||||
callback
|
||||
)
|
||||
},
|
||||
|
||||
setupLoginData(user, callback) {
|
||||
if (callback == null) {
|
||||
callback = function() {}
|
||||
}
|
||||
return this.populateTeamInvites(user, callback)
|
||||
this.populateTeamInvites(user, callback)
|
||||
}
|
||||
}
|
||||
module.exports = UserHandler
|
||||
|
|
|
@ -1,41 +1,21 @@
|
|||
/* 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 UserGetter = require('./UserGetter')
|
||||
const logger = require('logger-sharelatex')
|
||||
const UserDeleter = require('./UserDeleter')
|
||||
const UserUpdater = require('./UserUpdater')
|
||||
const sanitize = require('sanitizer')
|
||||
const AuthenticationController = require('../Authentication/AuthenticationController')
|
||||
const { ObjectId } = require('mongojs')
|
||||
|
||||
module.exports = UserController = {
|
||||
getLoggedInUsersPersonalInfo(req, res, next) {
|
||||
if (next == null) {
|
||||
next = function(error) {}
|
||||
}
|
||||
const user_id = AuthenticationController.getLoggedInUserId(req)
|
||||
const userId = AuthenticationController.getLoggedInUserId(req)
|
||||
logger.log(
|
||||
{ user_id },
|
||||
{ userId },
|
||||
'reciving request for getting logged in users personal info'
|
||||
)
|
||||
if (user_id == null) {
|
||||
if (!userId) {
|
||||
return next(new Error('User is not logged in'))
|
||||
}
|
||||
return UserGetter.getUser(
|
||||
user_id,
|
||||
UserGetter.getUser(
|
||||
userId,
|
||||
{
|
||||
first_name: true,
|
||||
last_name: true,
|
||||
|
@ -45,64 +25,55 @@ module.exports = UserController = {
|
|||
signUpDate: true
|
||||
},
|
||||
function(error, user) {
|
||||
if (error != null) {
|
||||
if (error) {
|
||||
return next(error)
|
||||
}
|
||||
return UserController.sendFormattedPersonalInfo(user, res, next)
|
||||
UserController.sendFormattedPersonalInfo(user, res, next)
|
||||
}
|
||||
)
|
||||
},
|
||||
|
||||
getPersonalInfo(req, res, next) {
|
||||
let query
|
||||
if (next == null) {
|
||||
next = function(error) {}
|
||||
}
|
||||
const { user_id } = req.params
|
||||
const userId = req.params.user_id
|
||||
|
||||
if (/^\d+$/.test(user_id)) {
|
||||
query = { 'overleaf.id': parseInt(user_id, 10) }
|
||||
} else if (/^[a-f0-9]{24}$/.test(user_id)) {
|
||||
query = { _id: ObjectId(user_id) }
|
||||
if (/^\d+$/.test(userId)) {
|
||||
query = { 'overleaf.id': parseInt(userId, 10) }
|
||||
} else if (/^[a-f0-9]{24}$/.test(userId)) {
|
||||
query = { _id: ObjectId(userId) }
|
||||
} else {
|
||||
return res.send(400)
|
||||
}
|
||||
|
||||
return UserGetter.getUser(
|
||||
UserGetter.getUser(
|
||||
query,
|
||||
{ _id: true, first_name: true, last_name: true, email: true },
|
||||
function(error, user) {
|
||||
logger.log(
|
||||
{ user_id: req.params.user_id },
|
||||
{ userId },
|
||||
'receiving request for getting users personal info'
|
||||
)
|
||||
if (error != null) {
|
||||
if (error) {
|
||||
return next(error)
|
||||
}
|
||||
if (user == null) {
|
||||
if (!user) {
|
||||
return res.send(404)
|
||||
}
|
||||
return UserController.sendFormattedPersonalInfo(user, res, next)
|
||||
UserController.sendFormattedPersonalInfo(user, res, next)
|
||||
}
|
||||
)
|
||||
},
|
||||
|
||||
sendFormattedPersonalInfo(user, res, next) {
|
||||
if (next == null) {
|
||||
next = function(error) {}
|
||||
}
|
||||
const info = UserController.formatPersonalInfo(user)
|
||||
return res.json(info)
|
||||
res.json(info)
|
||||
},
|
||||
|
||||
formatPersonalInfo(user, callback) {
|
||||
if (callback == null) {
|
||||
callback = function(error, info) {}
|
||||
}
|
||||
if (user == null) {
|
||||
if (!user) {
|
||||
return {}
|
||||
}
|
||||
const formatted_user = { id: user._id.toString() }
|
||||
const formattedUser = { id: user._id.toString() }
|
||||
for (let key of [
|
||||
'first_name',
|
||||
'last_name',
|
||||
|
@ -111,10 +82,10 @@ module.exports = UserController = {
|
|||
'role',
|
||||
'institution'
|
||||
]) {
|
||||
if (user[key] != null) {
|
||||
formatted_user[key] = user[key]
|
||||
if (user[key]) {
|
||||
formattedUser[key] = user[key]
|
||||
}
|
||||
}
|
||||
return formatted_user
|
||||
return formattedUser
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,29 +1,13 @@
|
|||
/* 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 UserInfoManager
|
||||
const UserGetter = require('./UserGetter')
|
||||
|
||||
module.exports = UserInfoManager = {
|
||||
getPersonalInfo(user_id, callback) {
|
||||
if (callback == null) {
|
||||
callback = function(error) {}
|
||||
}
|
||||
return UserGetter.getUser(
|
||||
user_id,
|
||||
const UserInfoManager = {
|
||||
getPersonalInfo(userId, callback) {
|
||||
UserGetter.getUser(
|
||||
userId,
|
||||
{ _id: true, first_name: true, last_name: true, email: true },
|
||||
callback
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = UserInfoManager
|
||||
|
|
|
@ -1,18 +1,3 @@
|
|||
/* eslint-disable
|
||||
camelcase,
|
||||
handle-callback-err,
|
||||
max-len,
|
||||
*/
|
||||
// TODO: This file was created by bulk-decaffeinate.
|
||||
// Fix any style issues and re-enable lint.
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS101: Remove unnecessary use of Array.from
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* DS103: Rewrite code to no longer use __guard__
|
||||
* DS207: Consider shorter variations of null checks
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
let UserSessionsManager
|
||||
const Settings = require('settings-sharelatex')
|
||||
const logger = require('logger-sharelatex')
|
||||
|
@ -28,26 +13,23 @@ module.exports = UserSessionsManager = {
|
|||
},
|
||||
|
||||
trackSession(user, sessionId, callback) {
|
||||
if (callback == null) {
|
||||
callback = function(err) {}
|
||||
}
|
||||
if (user == null) {
|
||||
if (!user) {
|
||||
logger.log({ sessionId }, 'no user to track, returning')
|
||||
return callback(null)
|
||||
}
|
||||
if (sessionId == null) {
|
||||
if (!sessionId) {
|
||||
logger.log({ user_id: user._id }, 'no sessionId to track, returning')
|
||||
return callback(null)
|
||||
}
|
||||
logger.log({ user_id: user._id, sessionId }, 'onLogin handler')
|
||||
const sessionSetKey = UserSessionsRedis.sessionSetKey(user)
|
||||
const value = UserSessionsManager._sessionKey(sessionId)
|
||||
return rclient
|
||||
rclient
|
||||
.multi()
|
||||
.sadd(sessionSetKey, value)
|
||||
.pexpire(sessionSetKey, `${Settings.cookieSessionLength}`) // in milliseconds
|
||||
.exec(function(err, response) {
|
||||
if (err != null) {
|
||||
if (err) {
|
||||
logger.warn(
|
||||
{ err, user_id: user._id, sessionSetKey },
|
||||
'error while adding session key to UserSessions set'
|
||||
|
@ -55,31 +37,31 @@ module.exports = UserSessionsManager = {
|
|||
return callback(err)
|
||||
}
|
||||
UserSessionsManager._checkSessions(user, function() {})
|
||||
return callback()
|
||||
callback()
|
||||
})
|
||||
},
|
||||
|
||||
untrackSession(user, sessionId, callback) {
|
||||
if (callback == null) {
|
||||
callback = function(err) {}
|
||||
if (!callback) {
|
||||
callback = function() {}
|
||||
}
|
||||
if (user == null) {
|
||||
if (!user) {
|
||||
logger.log({ sessionId }, 'no user to untrack, returning')
|
||||
return callback(null)
|
||||
}
|
||||
if (sessionId == null) {
|
||||
if (!sessionId) {
|
||||
logger.log({ user_id: user._id }, 'no sessionId to untrack, returning')
|
||||
return callback(null)
|
||||
}
|
||||
logger.log({ user_id: user._id, sessionId }, 'onLogout handler')
|
||||
const sessionSetKey = UserSessionsRedis.sessionSetKey(user)
|
||||
const value = UserSessionsManager._sessionKey(sessionId)
|
||||
return rclient
|
||||
rclient
|
||||
.multi()
|
||||
.srem(sessionSetKey, value)
|
||||
.pexpire(sessionSetKey, `${Settings.cookieSessionLength}`) // in milliseconds
|
||||
.exec(function(err, response) {
|
||||
if (err != null) {
|
||||
if (err) {
|
||||
logger.warn(
|
||||
{ err, user_id: user._id, sessionSetKey },
|
||||
'error while removing session key from UserSessions set'
|
||||
|
@ -87,18 +69,15 @@ module.exports = UserSessionsManager = {
|
|||
return callback(err)
|
||||
}
|
||||
UserSessionsManager._checkSessions(user, function() {})
|
||||
return callback()
|
||||
callback()
|
||||
})
|
||||
},
|
||||
|
||||
getAllUserSessions(user, exclude, callback) {
|
||||
if (callback == null) {
|
||||
callback = function(err, sessionKeys) {}
|
||||
}
|
||||
exclude = _.map(exclude, UserSessionsManager._sessionKey)
|
||||
const sessionSetKey = UserSessionsRedis.sessionSetKey(user)
|
||||
return rclient.smembers(sessionSetKey, function(err, sessionKeys) {
|
||||
if (err != null) {
|
||||
rclient.smembers(sessionSetKey, function(err, sessionKeys) {
|
||||
if (err) {
|
||||
logger.warn(
|
||||
{ user_id: user._id },
|
||||
'error getting all session keys for user from redis'
|
||||
|
@ -111,58 +90,53 @@ module.exports = UserSessionsManager = {
|
|||
return callback(null, [])
|
||||
}
|
||||
|
||||
return Async.mapSeries(
|
||||
sessionKeys,
|
||||
(k, cb) => rclient.get(k, cb),
|
||||
function(err, sessions) {
|
||||
if (err != null) {
|
||||
logger.warn(
|
||||
{ user_id: user._id },
|
||||
'error getting all sessions for user from redis'
|
||||
)
|
||||
return callback(err)
|
||||
}
|
||||
|
||||
const result = []
|
||||
for (let session of Array.from(sessions)) {
|
||||
if (session === null) {
|
||||
continue
|
||||
}
|
||||
session = JSON.parse(session)
|
||||
const session_user =
|
||||
(session != null ? session.user : undefined) ||
|
||||
__guard__(
|
||||
session != null ? session.passport : undefined,
|
||||
x => x.user
|
||||
)
|
||||
result.push({
|
||||
ip_address: session_user.ip_address,
|
||||
session_created: session_user.session_created
|
||||
})
|
||||
}
|
||||
|
||||
return callback(null, result)
|
||||
Async.mapSeries(sessionKeys, (k, cb) => rclient.get(k, cb), function(
|
||||
err,
|
||||
sessions
|
||||
) {
|
||||
if (err) {
|
||||
logger.warn(
|
||||
{ user_id: user._id },
|
||||
'error getting all sessions for user from redis'
|
||||
)
|
||||
return callback(err)
|
||||
}
|
||||
)
|
||||
|
||||
const result = []
|
||||
for (let session of Array.from(sessions)) {
|
||||
if (!session) {
|
||||
continue
|
||||
}
|
||||
session = JSON.parse(session)
|
||||
let sessionUser = session.passport && session.passport.user
|
||||
if (!sessionUser) {
|
||||
sessionUser = session.user
|
||||
}
|
||||
|
||||
result.push({
|
||||
ip_address: sessionUser.ip_address,
|
||||
session_created: sessionUser.session_created
|
||||
})
|
||||
}
|
||||
|
||||
callback(null, result)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
revokeAllUserSessions(user, retain, callback) {
|
||||
if (callback == null) {
|
||||
callback = function(err) {}
|
||||
}
|
||||
if (retain == null) {
|
||||
if (!retain) {
|
||||
retain = []
|
||||
}
|
||||
retain = retain.map(i => UserSessionsManager._sessionKey(i))
|
||||
if (user == null) {
|
||||
if (!user) {
|
||||
logger.log({}, 'no user to revoke sessions for, returning')
|
||||
return callback(null)
|
||||
}
|
||||
logger.log({ user_id: user._id }, 'revoking all existing sessions for user')
|
||||
const sessionSetKey = UserSessionsRedis.sessionSetKey(user)
|
||||
return rclient.smembers(sessionSetKey, function(err, sessionKeys) {
|
||||
if (err != null) {
|
||||
rclient.smembers(sessionSetKey, function(err, sessionKeys) {
|
||||
if (err) {
|
||||
logger.warn(
|
||||
{ err, user_id: user._id, sessionSetKey },
|
||||
'error getting contents of UserSessions set'
|
||||
|
@ -187,65 +161,59 @@ module.exports = UserSessionsManager = {
|
|||
|
||||
const deletions = keysToDelete.map(k => cb => rclient.del(k, cb))
|
||||
|
||||
return Async.series(deletions, function(err, _result) {
|
||||
if (err != null) {
|
||||
Async.series(deletions, function(err, _result) {
|
||||
if (err) {
|
||||
logger.warn(
|
||||
{ err, user_id: user._id, sessionSetKey },
|
||||
'errror revoking all sessions for user'
|
||||
)
|
||||
return callback(err)
|
||||
}
|
||||
return rclient.srem(sessionSetKey, keysToDelete, function(err) {
|
||||
if (err != null) {
|
||||
rclient.srem(sessionSetKey, keysToDelete, function(err) {
|
||||
if (err) {
|
||||
logger.warn(
|
||||
{ err, user_id: user._id, sessionSetKey },
|
||||
'error removing session set for user'
|
||||
)
|
||||
return callback(err)
|
||||
}
|
||||
return callback(null)
|
||||
callback(null)
|
||||
})
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
touch(user, callback) {
|
||||
if (callback == null) {
|
||||
callback = function(err) {}
|
||||
}
|
||||
if (user == null) {
|
||||
if (!user) {
|
||||
logger.log({}, 'no user to touch sessions for, returning')
|
||||
return callback(null)
|
||||
}
|
||||
const sessionSetKey = UserSessionsRedis.sessionSetKey(user)
|
||||
return rclient.pexpire(
|
||||
rclient.pexpire(
|
||||
sessionSetKey,
|
||||
`${Settings.cookieSessionLength}`, // in milliseconds
|
||||
function(err, response) {
|
||||
if (err != null) {
|
||||
if (err) {
|
||||
logger.warn(
|
||||
{ err, user_id: user._id },
|
||||
'error while updating ttl on UserSessions set'
|
||||
)
|
||||
return callback(err)
|
||||
}
|
||||
return callback(null)
|
||||
callback(null)
|
||||
}
|
||||
)
|
||||
},
|
||||
|
||||
_checkSessions(user, callback) {
|
||||
if (callback == null) {
|
||||
callback = function(err) {}
|
||||
}
|
||||
if (user == null) {
|
||||
if (!user) {
|
||||
logger.log({}, 'no user, returning')
|
||||
return callback(null)
|
||||
}
|
||||
logger.log({ user_id: user._id }, 'checking sessions for user')
|
||||
const sessionSetKey = UserSessionsRedis.sessionSetKey(user)
|
||||
return rclient.smembers(sessionSetKey, function(err, sessionKeys) {
|
||||
if (err != null) {
|
||||
rclient.smembers(sessionSetKey, function(err, sessionKeys) {
|
||||
if (err) {
|
||||
logger.warn(
|
||||
{ err, user_id: user._id, sessionSetKey },
|
||||
'error getting contents of UserSessions set'
|
||||
|
@ -256,39 +224,30 @@ module.exports = UserSessionsManager = {
|
|||
{ user_id: user._id, count: sessionKeys.length },
|
||||
'checking sessions for user'
|
||||
)
|
||||
return Async.series(
|
||||
Async.series(
|
||||
sessionKeys.map(key => next =>
|
||||
rclient.get(key, function(err, val) {
|
||||
if (err != null) {
|
||||
if (err) {
|
||||
return next(err)
|
||||
}
|
||||
if (val == null) {
|
||||
if (!val) {
|
||||
logger.log(
|
||||
{ user_id: user._id, key },
|
||||
'>> removing key from UserSessions set'
|
||||
)
|
||||
return rclient.srem(sessionSetKey, key, function(err, result) {
|
||||
if (err != null) {
|
||||
return next(err)
|
||||
}
|
||||
return next(null)
|
||||
rclient.srem(sessionSetKey, key, function(err, result) {
|
||||
return next(err)
|
||||
})
|
||||
} else {
|
||||
return next()
|
||||
next()
|
||||
}
|
||||
})
|
||||
),
|
||||
function(err, results) {
|
||||
logger.log({ user_id: user._id }, 'done checking sessions for user')
|
||||
return callback(err)
|
||||
callback(err)
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function __guard__(value, transform) {
|
||||
return typeof value !== 'undefined' && value !== null
|
||||
? transform(value)
|
||||
: undefined
|
||||
}
|
||||
|
|
|
@ -1,13 +1,7 @@
|
|||
/* eslint-disable
|
||||
no-unused-vars,
|
||||
*/
|
||||
// TODO: This file was created by bulk-decaffeinate.
|
||||
// Fix any style issues and re-enable lint.
|
||||
let Redis
|
||||
const RedisWrapper = require('../../infrastructure/RedisWrapper')
|
||||
const rclient = RedisWrapper.client('websessions')
|
||||
|
||||
module.exports = Redis = {
|
||||
const UserSessionsRedis = {
|
||||
client() {
|
||||
return rclient
|
||||
},
|
||||
|
@ -16,3 +10,4 @@ module.exports = Redis = {
|
|||
return `UserSessions:{${user._id}}`
|
||||
}
|
||||
}
|
||||
module.exports = UserSessionsRedis
|
||||
|
|
Loading…
Reference in a new issue