2014-05-19 06:50:32 -04:00
|
|
|
logger = require("logger-sharelatex")
|
2014-02-12 05:23:40 -05:00
|
|
|
mongojs = require("../../infrastructure/mongojs")
|
2017-04-03 11:18:30 -04:00
|
|
|
metrics = require("metrics-sharelatex")
|
2014-02-12 05:23:40 -05:00
|
|
|
db = mongojs.db
|
2018-05-25 07:04:09 -04:00
|
|
|
async = require("async")
|
2014-02-12 05:23:40 -05:00
|
|
|
ObjectId = mongojs.ObjectId
|
2018-05-23 10:12:23 -04:00
|
|
|
UserGetter = require("./UserGetter")
|
2018-07-10 15:49:24 -04:00
|
|
|
{ addAffiliation, removeAffiliation } = require("../Institutions/InstitutionsAPI")
|
2018-07-11 08:57:35 -04:00
|
|
|
FeaturesUpdater = require("../Subscription/FeaturesUpdater")
|
2018-06-19 08:55:34 -04:00
|
|
|
EmailHelper = require "../Helpers/EmailHelper"
|
|
|
|
Errors = require "../Errors/Errors"
|
2018-07-16 08:26:52 -04:00
|
|
|
Settings = require "settings-sharelatex"
|
|
|
|
request = require 'request'
|
2018-08-07 16:38:31 -04:00
|
|
|
NewsletterManager = require "../Newsletter/NewsletterManager"
|
2014-02-12 05:23:40 -05:00
|
|
|
|
|
|
|
module.exports = UserUpdater =
|
|
|
|
updateUser: (query, update, callback = (error) ->) ->
|
|
|
|
if typeof query == "string"
|
|
|
|
query = _id: ObjectId(query)
|
|
|
|
else if query instanceof ObjectId
|
|
|
|
query = _id: query
|
2018-05-25 07:04:09 -04:00
|
|
|
else if typeof query._id == "string"
|
|
|
|
query._id = ObjectId(query._id)
|
2014-02-12 05:23:40 -05:00
|
|
|
|
|
|
|
db.users.update query, update, callback
|
2014-05-16 12:29:54 -04:00
|
|
|
|
|
|
|
|
2018-05-25 07:04:09 -04:00
|
|
|
#
|
|
|
|
# DEPRECATED
|
|
|
|
#
|
|
|
|
# Change the user's main email address by adding a new email, switching the
|
|
|
|
# default email and removing the old email. Prefer manipulating multiple
|
|
|
|
# emails and the default rather than calling this method directly
|
|
|
|
#
|
|
|
|
changeEmailAddress: (userId, newEmail, callback)->
|
2018-07-03 14:58:37 -04:00
|
|
|
newEmail = EmailHelper.parseEmail(newEmail)
|
|
|
|
return callback(new Error('invalid email')) if !newEmail?
|
2018-05-25 07:04:09 -04:00
|
|
|
logger.log userId: userId, newEmail: newEmail, "updaing email address of user"
|
|
|
|
|
|
|
|
oldEmail = null
|
|
|
|
async.series [
|
|
|
|
(cb) ->
|
|
|
|
UserGetter.getUserEmail userId, (error, email) ->
|
|
|
|
oldEmail = email
|
|
|
|
cb(error)
|
|
|
|
(cb) -> UserUpdater.addEmailAddress userId, newEmail, cb
|
|
|
|
(cb) -> UserUpdater.setDefaultEmailAddress userId, newEmail, cb
|
|
|
|
(cb) -> UserUpdater.removeEmailAddress userId, oldEmail, cb
|
|
|
|
], callback
|
|
|
|
|
|
|
|
|
|
|
|
# Add a new email address for the user. Email cannot be already used by this
|
|
|
|
# or any other user
|
2018-06-19 07:46:15 -04:00
|
|
|
addEmailAddress: (userId, newEmail, affiliationOptions, callback) ->
|
|
|
|
unless callback? # affiliationOptions is optional
|
|
|
|
callback = affiliationOptions
|
|
|
|
affiliationOptions = {}
|
2018-07-03 14:58:37 -04:00
|
|
|
newEmail = EmailHelper.parseEmail(newEmail)
|
|
|
|
return callback(new Error('invalid email')) if !newEmail?
|
2018-06-19 07:46:15 -04:00
|
|
|
|
2018-05-28 10:08:37 -04:00
|
|
|
UserGetter.ensureUniqueEmailAddress newEmail, (error) =>
|
2018-05-25 07:04:09 -04:00
|
|
|
return callback(error) if error?
|
|
|
|
|
2018-06-19 07:46:15 -04:00
|
|
|
addAffiliation userId, newEmail, affiliationOptions, (error) =>
|
2018-05-25 07:04:09 -04:00
|
|
|
if error?
|
2018-07-04 09:47:49 -04:00
|
|
|
logger.err error: error, 'problem adding affiliation while adding email'
|
2018-05-25 07:04:09 -04:00
|
|
|
return callback(error)
|
2018-06-19 07:46:15 -04:00
|
|
|
|
|
|
|
update = $push: emails: email: newEmail, createdAt: new Date()
|
|
|
|
@updateUser userId, update, (error) ->
|
|
|
|
if error?
|
|
|
|
logger.err error: error, 'problem updating users emails'
|
|
|
|
return callback(error)
|
|
|
|
callback()
|
2014-05-16 12:29:54 -04:00
|
|
|
|
2018-06-27 12:29:56 -04:00
|
|
|
|
2018-05-25 07:04:09 -04:00
|
|
|
# remove one of the user's email addresses. The email cannot be the user's
|
|
|
|
# default email address
|
|
|
|
removeEmailAddress: (userId, email, callback) ->
|
2018-07-03 14:58:37 -04:00
|
|
|
email = EmailHelper.parseEmail(email)
|
|
|
|
return callback(new Error('invalid email')) if !email?
|
2018-06-19 07:46:15 -04:00
|
|
|
removeAffiliation userId, email, (error) =>
|
2018-05-25 07:04:09 -04:00
|
|
|
if error?
|
2018-06-19 07:46:15 -04:00
|
|
|
logger.err error: error, 'problem removing affiliation'
|
2018-05-25 07:04:09 -04:00
|
|
|
return callback(error)
|
2018-06-19 07:46:15 -04:00
|
|
|
|
|
|
|
query = _id: userId, email: $ne: email
|
|
|
|
update = $pull: emails: email: email
|
|
|
|
@updateUser query, update, (error, res) ->
|
|
|
|
if error?
|
|
|
|
logger.err error:error, 'problem removing users email'
|
|
|
|
return callback(error)
|
|
|
|
if res.n == 0
|
2018-06-25 07:46:46 -04:00
|
|
|
return callback(new Error('Cannot remove email'))
|
2018-06-19 07:46:15 -04:00
|
|
|
callback()
|
2018-05-25 07:04:09 -04:00
|
|
|
|
|
|
|
|
|
|
|
# set the default email address by setting the `email` attribute. The email
|
|
|
|
# must be one of the user's multiple emails (`emails` attribute)
|
|
|
|
setDefaultEmailAddress: (userId, email, callback) ->
|
2018-07-03 14:58:37 -04:00
|
|
|
email = EmailHelper.parseEmail(email)
|
|
|
|
return callback(new Error('invalid email')) if !email?
|
2018-08-08 08:15:51 -04:00
|
|
|
UserGetter.getUserEmail userId, (error, oldEmail) =>
|
|
|
|
if err?
|
2018-05-25 07:04:09 -04:00
|
|
|
return callback(error)
|
2018-08-08 08:15:51 -04:00
|
|
|
query = _id: userId, 'emails.email': email
|
|
|
|
update = $set: email: email
|
|
|
|
@updateUser query, update, (error, res) ->
|
|
|
|
if error?
|
|
|
|
logger.err error:error, 'problem setting default emails'
|
|
|
|
return callback(error)
|
|
|
|
else if res.n == 0 # TODO: Check n or nMatched?
|
|
|
|
return callback(new Error('Default email does not belong to user'))
|
|
|
|
else
|
2018-08-31 06:16:28 -04:00
|
|
|
NewsletterManager.changeEmail oldEmail, email, ->
|
2018-08-31 06:49:45 -04:00
|
|
|
callback()
|
2018-08-08 08:15:51 -04:00
|
|
|
|
|
|
|
|
2018-05-25 07:04:09 -04:00
|
|
|
|
2018-07-16 08:26:52 -04:00
|
|
|
updateV1AndSetDefaultEmailAddress: (userId, email, callback) ->
|
|
|
|
@updateEmailAddressInV1 userId, email, (error) =>
|
|
|
|
return callback(error) if error?
|
|
|
|
@setDefaultEmailAddress userId, email, callback
|
|
|
|
|
|
|
|
updateEmailAddressInV1: (userId, newEmail, callback) ->
|
|
|
|
if !Settings.apis?.v1?.url?
|
|
|
|
return callback()
|
|
|
|
UserGetter.getUser userId, { 'overleaf.id': 1, emails: 1 }, (error, user) ->
|
|
|
|
return callback(error) if error?
|
|
|
|
return callback(new Errors.NotFoundError('no user found')) if !user?
|
|
|
|
if !user.overleaf?.id?
|
|
|
|
return callback()
|
|
|
|
newEmailIsConfirmed = false
|
|
|
|
for email in user.emails
|
|
|
|
if email.email == newEmail and email.confirmedAt?
|
|
|
|
newEmailIsConfirmed = true
|
|
|
|
break
|
|
|
|
if !newEmailIsConfirmed
|
|
|
|
return callback(new Errors.UnconfirmedEmailError("can't update v1 with unconfirmed email"))
|
|
|
|
request {
|
|
|
|
baseUrl: Settings.apis.v1.url
|
|
|
|
url: "/api/v1/sharelatex/users/#{user.overleaf.id}/email"
|
|
|
|
method: 'PUT'
|
|
|
|
auth:
|
|
|
|
user: Settings.apis.v1.user
|
|
|
|
pass: Settings.apis.v1.pass
|
|
|
|
sendImmediately: true
|
2018-07-17 06:12:09 -04:00
|
|
|
json:
|
|
|
|
user:
|
|
|
|
email: newEmail
|
2018-07-16 08:26:52 -04:00
|
|
|
timeout: 5 * 1000
|
|
|
|
}, (error, response, body) ->
|
|
|
|
if error?
|
|
|
|
error = new Errors.V1ConnectionError('No V1 connection') if error.code == 'ECONNREFUSED'
|
|
|
|
return callback(error)
|
2018-07-16 12:25:52 -04:00
|
|
|
if response.statusCode == 409 # Conflict
|
|
|
|
return callback(new Errors.EmailExistsError('email exists in v1'))
|
|
|
|
else if 200 <= response.statusCode < 300
|
2018-07-16 08:26:52 -04:00
|
|
|
return callback()
|
|
|
|
else
|
|
|
|
return callback new Error("non-success code from v1: #{response.statusCode}")
|
|
|
|
|
2018-08-01 04:37:14 -04:00
|
|
|
confirmEmail: (userId, email, confirmedAt, callback) ->
|
|
|
|
if arguments.length == 3
|
|
|
|
callback = confirmedAt
|
|
|
|
confirmedAt = new Date()
|
2018-06-19 08:55:34 -04:00
|
|
|
email = EmailHelper.parseEmail(email)
|
|
|
|
return callback(new Error('invalid email')) if !email?
|
|
|
|
logger.log {userId, email}, 'confirming user email'
|
2018-08-09 03:20:34 -04:00
|
|
|
addAffiliation userId, email, {confirmedAt: confirmedAt}, (error) =>
|
2018-07-04 09:47:49 -04:00
|
|
|
if error?
|
|
|
|
logger.err error: error, 'problem adding affiliation while confirming email'
|
|
|
|
return callback(error)
|
|
|
|
|
|
|
|
query =
|
|
|
|
_id: userId
|
|
|
|
'emails.email': email
|
|
|
|
update =
|
|
|
|
$set:
|
2018-08-01 04:37:14 -04:00
|
|
|
'emails.$.confirmedAt': confirmedAt
|
2018-07-04 09:47:49 -04:00
|
|
|
@updateUser query, update, (error, res) ->
|
|
|
|
return callback(error) if error?
|
|
|
|
logger.log {res, userId, email}, "tried to confirm email"
|
|
|
|
if res.n == 0
|
|
|
|
return callback(new Errors.NotFoundError('user id and email do no match'))
|
2018-07-11 08:57:35 -04:00
|
|
|
FeaturesUpdater.refreshFeatures userId, true, callback
|
2018-06-19 08:55:34 -04:00
|
|
|
|
2018-05-25 07:04:09 -04:00
|
|
|
[
|
|
|
|
'updateUser'
|
|
|
|
'changeEmailAddress'
|
|
|
|
'setDefaultEmailAddress'
|
|
|
|
'addEmailAddress'
|
|
|
|
'removeEmailAddress'
|
|
|
|
].map (method) ->
|
|
|
|
metrics.timeAsyncMethod(UserUpdater, method, 'mongo.UserUpdater', logger)
|