overleaf/services/web/app/coffee/Features/User/UserGetter.coffee
2018-06-27 12:09:58 +01:00

122 lines
4 KiB
CoffeeScript

mongojs = require("../../infrastructure/mongojs")
metrics = require('metrics-sharelatex')
logger = require('logger-sharelatex')
db = mongojs.db
ObjectId = mongojs.ObjectId
settings = require "settings-sharelatex"
request = require "request"
module.exports = UserGetter =
getUser: (query, projection, callback = (error, user) ->) ->
if query?.email?
return callback(new Error("Don't use getUser to find user by email"), null)
if arguments.length == 2
callback = projection
projection = {}
if typeof query == "string"
try
query = _id: ObjectId(query)
catch e
return callback(null, null)
else if query instanceof ObjectId
query = _id: query
db.users.findOne query, projection, callback
getUserEmail: (userId, callback = (error, email) ->) ->
@getUser userId, { email: 1 }, (error, user) ->
callback(error, user?.email)
getUserFullEmails: (userId, callback = (error, emails) ->) ->
@getUser userId, { email: 1, emails: 1 }, (error, user) ->
return callback error if error?
return callback new Error('User not Found') unless user
getAffiliations userId, (error, affiliationsData) ->
return callback error if error?
callback null, decorateFullEmails(user.email, user.emails, affiliationsData)
getUserByMainEmail: (email, projection, callback = (error, user) ->) ->
email = email.trim()
if arguments.length == 2
callback = projection
projection = {}
db.users.findOne email: email, projection, callback
getUserByAnyEmail: (email, projection, callback = (error, user) ->) ->
email = email.trim()
if arguments.length == 2
callback = projection
projection = {}
# $exists: true MUST be set to use the partial index
query = emails: { $exists: true }, 'emails.email': email
db.users.findOne query, projection, (error, user) =>
return callback(error, user) if error? or user?
# While multiple emails are being rolled out, check for the main email as
# well
@getUserByMainEmail email, projection, callback
getUsers: (user_ids, projection, callback = (error, users) ->) ->
try
user_ids = user_ids.map (u) -> ObjectId(u.toString())
catch error
return callback error
db.users.find { _id: { $in: user_ids} }, projection, callback
getUserOrUserStubById: (user_id, projection, callback = (error, user) ->) ->
try
query = _id: ObjectId(user_id.toString())
catch e
return callback(new Error(e))
db.users.findOne query, projection, (error, user) ->
return callback(error) if error?
return callback(null, user) if user?
db.userstubs.findOne query, projection, callback
# check for duplicate email address. This is also enforced at the DB level
ensureUniqueEmailAddress: (newEmail, callback) ->
@getUserByAnyEmail newEmail, (error, user) ->
return callback(message: 'alread_exists') if user?
callback(error)
decorateFullEmails = (defaultEmail, emailsData, affiliationsData) ->
emailsData.map (emailData) ->
emailData.default = emailData.email == defaultEmail
affiliation = affiliationsData.find (aff) -> aff.email == emailData.email
if affiliation?
{ institution, inferred, role, department } = affiliation
emailData.affiliation = { institution, inferred, role, department }
else
emailsData.affiliation = null
emailData
getAffiliations = (userId, callback = (error) ->) ->
return callback(null, []) unless settings?.apis?.v1?.url # service is not configured
request {
method: 'GET'
url: "#{settings.apis.v1.url}/api/v2/users/#{userId.toString()}/affiliations"
auth: { user: settings.apis.v1.user, pass: settings.apis.v1.pass }
json: true,
timeout: 20 * 1000
}, (error, response, body) ->
return callback(error) if error?
unless 200 <= response.statusCode < 300
errorMessage = "Couldn't get affiliations: #{response.statusCode}"
return callback(new Error(errorMessage))
callback(null, body)
[
'getUser',
'getUserEmail',
'getUserByMainEmail',
'getUserByAnyEmail',
'getUsers',
'getUserOrUserStubById',
'ensureUniqueEmailAddress',
].map (method) ->
metrics.timeAsyncMethod UserGetter, method, 'mongo.UserGetter', logger