Created
February 26, 2019 16:35
-
-
Save emil-alexandrescu/c0edef61870a7093f0108d1ad3eb47df to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const _ = require('lodash'); | |
const moment = require('moment'); | |
const shortid = require('shortid'); | |
const Promise = require('bluebird'); | |
const User = require('../models/user'); | |
const Team = require('../models/team'); | |
const RoleService = require('../services/role.service'); | |
const APIError = require('../utils/api-error'); | |
const sendEmail = require('../utils/send-mail'); | |
const config = require('../../config/config'); | |
const { STATUS } | |
= require('../constants/user'); | |
function getQuery(filterName, filterValue) { | |
return Promise.resolve({ [filterName]: filterValue }); | |
} | |
function getSorts(sorts) { | |
return sorts.map(sort => sort.split(' ')); | |
} | |
function revokeToken(user) { | |
user.revokeTokenBefore = new Date(); | |
return user.save(); | |
} | |
/** | |
* @param {Object} data | |
*/ | |
function create(data) { | |
const newUser = new User( | |
_.pick(data, 'email', 'username', 'lastname', 'avatar', 'role', 'firstname', 'teams') | |
); | |
// explicitly set status to PENDING, since user hasn't accepted invitation yet | |
newUser.status = STATUS.PENDING; | |
return User.hash(shortid.generate()) | |
.then((password) => { | |
newUser.password = password; | |
newUser.resetToken = shortid.generate(); | |
newUser.resetExpiresIn = moment().add(config.resetPasswordExpiresIn, 'minutes').toDate(); | |
return newUser.save(); | |
}) | |
.then((user) => { | |
if (data.teams) { | |
return Team.update( | |
{ _id: { $in: data.teams || [] } }, | |
{ $addToSet: { members: user._id } }, | |
{ multi: true } | |
).then(() => user); | |
} | |
return user; | |
}) | |
.then(user => | |
sendEmail({ | |
to: [{ email: user.email, name: `${user.firstname} ${user.lastname}` }], | |
template: 'torrent-welcome', | |
emailVars: { | |
first_name: user.firstname, | |
last_name: user.lastname, | |
welcome_link: `${config.siteUrl}/reset-password?token=${user.resetToken}` | |
} | |
}).then(() => user) | |
); | |
} | |
/** | |
* @param {User} user | |
* @param {Object} data | |
*/ | |
function update(user, data) { | |
let promise = Promise.resolve(); | |
if (data.teams) { | |
promise = Team.update( | |
{}, | |
{ $pull: { members: user._id } }, | |
{ multi: true } | |
) | |
.then(() => Team.update( | |
{ _id: { $in: data.teams || [] } }, | |
{ $addToSet: { members: user._id } }, | |
{ multi: true } | |
)); | |
} | |
if (data.password) { | |
promise = promise | |
.then(() => User.hash(data.password)) | |
.then((password) => { | |
user.password = password; | |
}); | |
} | |
// revoke tokens in such cases | |
if (data.role && data.role !== user.role._id.toString()) { | |
promise = promise.then(() => revokeToken(user)); | |
} else if (data.password) { | |
promise = promise.then(() => revokeToken(user)); | |
} | |
return promise | |
.then(() => { | |
Object.assign(user, data); | |
return user.save(); | |
}); | |
} | |
/** | |
* @param {User} user | |
*/ | |
function remove(user) { | |
return user.update({ | |
status: STATUS.DELETED, | |
name: `DELETED_ON_${new Date().getTime()}_${user.username}` | |
}) | |
.then(result => Team.update( | |
{ _id: { $in: user.teams || [] } }, | |
{ $pull: { members: user._id } }, | |
{ multi: true } | |
).then(() => result)); | |
} | |
/** | |
* @param {Number} page | |
* @param {Number} size | |
* @param {Object} filters | |
* @param {Array<String>} sorts | |
*/ | |
function list(filters = {}, sorts = [], page = 0, size = 1000, currentUser) { | |
return Promise.all( | |
Object.keys(filters).map( | |
filterName => getQuery(filterName, filters[filterName]) | |
).concat([RoleService.getManagableRoles(currentUser.role)]) | |
) | |
.then((result) => { | |
const managableRoles = result.pop(); | |
const queries = result; | |
const where = { | |
status: { $ne: STATUS.DELETED }, | |
role: { $in: managableRoles.map(r => r._id || r) } | |
}; | |
queries.forEach(query => Object.assign(where, query)); | |
return Promise.all([ | |
User.find(where) | |
.populate([{ | |
path: 'role', select: '_id name permissions' | |
}, { | |
path: 'teams', select: 'name' | |
}]) | |
.sort(getSorts(sorts)) | |
.skip(page * size) | |
.limit(size) | |
.lean(), | |
User.count(where) | |
]) | |
.spread((users, count) => ({ | |
pagination: { | |
currentPage: page, | |
numPages: Math.ceil(count / size) | |
}, | |
users | |
})); | |
}); | |
} | |
/** | |
* @param username {string} - user username | |
* @returns {Promise} | |
**/ | |
function findByUsername(username) { | |
return User.findOne({ | |
username, | |
status: { | |
$ne: STATUS.DELETED | |
} | |
}) | |
.populate([ | |
{ path: 'role', select: '_id name permissions' }, | |
{ path: 'teams', select: '_id name' } | |
]) | |
.then((user) => { | |
if (!user) { | |
const err = new APIError('User with provided username not found', 401, true); | |
throw err; | |
} | |
return user; | |
}); | |
} | |
module.exports = { | |
create, | |
update, | |
remove, | |
list, | |
findByUsername, | |
revokeToken | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment