Initial commit
This commit is contained in:
703
models/user.js
Normal file
703
models/user.js
Normal file
@@ -0,0 +1,703 @@
|
||||
const Authentication = require('../modules/authentication');
|
||||
const Mongoose = require('mongoose');
|
||||
const Reset = require('./reset');
|
||||
const Settings = require('./settings');
|
||||
|
||||
const UserSchema = new Mongoose.Schema({
|
||||
userName: { type: String, required: true, unique: true },
|
||||
password: { type: String },
|
||||
name: { first: { type: String, required: true }, last: { type: String, required: true } },
|
||||
title: String,
|
||||
email: { type: String, required: true, unique: true },
|
||||
permission: { type: Schema.Types.ObjectId, ref: 'roles', required: true, default: '59e6e1ab9bd9c04c803a0bc0' },
|
||||
avatar: String,
|
||||
settings: [ Settings.schema ],
|
||||
forceReset: { type: Boolean, default: true },
|
||||
updated_at: { type: Date, default: Date.now }
|
||||
});
|
||||
|
||||
UserSchema.pre('findOneAndUpdate', function (next) {
|
||||
var self = this;
|
||||
|
||||
this.update({}, { $set: { updated_at: Date.now() } });
|
||||
|
||||
if (this._update.$set.settings && this._update.$set.settings.length) {
|
||||
|
||||
}
|
||||
|
||||
if (this._update.$set.password && this._update.$set.confirmPassword && (this._update.$set.password == this._update.$set.confirmPassword)) {
|
||||
delete this._update.$set.confirmPassword;
|
||||
|
||||
if (this._update.$set.currentPassword) {
|
||||
confirmPassword(this._conditions.userName, this._update.$set.currentPassword, (err, valid) => {
|
||||
if (err || !valid) {
|
||||
err = new Error({ success: false, message: 'There was an error validating the current password.', err: (err || null) });
|
||||
next(err);
|
||||
}
|
||||
|
||||
if (valid) {
|
||||
delete this._update.$set.currentPassword;
|
||||
hashPassword(this._update.$set.password, (err, hashedPassword) => {
|
||||
self.update({}, { $set: { password: hashedPassword } });
|
||||
self.update({}, { $set: { forceReset: false } });
|
||||
next();
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
hashPassword(this._update.$set.password, (err, hashedPassword) => {
|
||||
self.update({}, { $set: { password: hashedPassword } });
|
||||
self.update({}, { $set: { forceReset: false } });
|
||||
next();
|
||||
});
|
||||
}
|
||||
} else if (this._update.$set.password && this._update.$set.confirmPassword && (this._update.$set.password != this._update.$set.confirmPassword)) {
|
||||
let err = new Error({ success: false, message: 'There was an error saving the updated password.'});
|
||||
next(err);
|
||||
} else if (!this._update.$set.password && !this._update.$set.confirmPassword) {
|
||||
next();
|
||||
}
|
||||
});
|
||||
|
||||
UserSchema.post('save', function (err, res, next) {
|
||||
if (err.name === 'MongoError' && err.code === 11000) {
|
||||
next(new Error('There was a duplicate key error'));
|
||||
} else if (err) {
|
||||
next(err);
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
});
|
||||
|
||||
const UserModel = Mongoose.model('users', UserSchema);
|
||||
|
||||
function hashPassword (password, callback) {
|
||||
callback = callback || false;
|
||||
|
||||
Authentication.hashPassword(password, (err, password) => {
|
||||
if (err !== null) {
|
||||
err = new Error({ success: false, message: 'There was an error hashing the updated password.', err: err });
|
||||
console.error('[updateUser:hashPassword] ', err);
|
||||
|
||||
if (callback) {
|
||||
callback(err, null);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (password) {
|
||||
var result = password.toString('hex');
|
||||
|
||||
if (callback) {
|
||||
callback(null, result);
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function confirmPassword (username, passwordToValidate, callback) {
|
||||
callback = callback || false;
|
||||
|
||||
UserModel.findById({ userName: username }, (err, user) => {
|
||||
if (err !== null) {
|
||||
err = new Error({ success: false, message: 'There was an error locating the user.', err: (err || null) });
|
||||
console.error('[updateUser:confirmPassword] ', err);
|
||||
|
||||
if (callback) {
|
||||
callback(err, null);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (user) {
|
||||
Authentication.verifyPassword(passwordToValidate, Buffer.from(storedUser.password, 'hex'), (err, valid) => {
|
||||
if (err !== null || !valid) {
|
||||
err = new Error({ success: false, message: (!err && !valid ? 'The current password was incorrect.' : 'There was an error attempting to validate the password.'), err: (err || null) });
|
||||
console.error('[updateUser:confirmPassword] ', { err: err, valid: valid });
|
||||
|
||||
if (callback) {
|
||||
callback(err, null);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (valid) {
|
||||
if (callback) {
|
||||
callback(null, valid);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
adminUpdatePassword: (e, username, password) => {
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
UserModel.findOneAndUpdate({ userName: username }, { $set: password }, { new: true }, (err, result) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
|
||||
if (result) {
|
||||
resolve(result);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
promise.then((result) => {
|
||||
if (e) {
|
||||
e.emit('adminUpdatePassword', null, result);
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
if (e) {
|
||||
e.emit('adminUpdatePassword', err, null);
|
||||
} else {
|
||||
return err;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
authenticateUser: (e, login, headers) => {
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
var loginObject, user;
|
||||
|
||||
UserModel
|
||||
.findOne({ userName: login.userName }, 'userName name title email password permission avatar settings forceReset')
|
||||
.populate('permission', 'name disabled manageRoles manageUsers manageCategories manageAppPreferences deleteVendor addVendorTag addVendorSample addVendorComment editVendor addNewVendor viewPrivateDetails viewPublicDetails')
|
||||
.exec((err, result) => {
|
||||
if (err) {
|
||||
loginObject = {
|
||||
status: 200,
|
||||
authorized: false,
|
||||
err: {
|
||||
id: '005',
|
||||
code: '[UMAU005]',
|
||||
string: 'There was an error authenticating the user.'
|
||||
}
|
||||
}
|
||||
console.log('[UserModel::authenticateUser] Error finding user', { err: err, username: login.userName });
|
||||
resolve(loginObject);
|
||||
}
|
||||
|
||||
if (result) {
|
||||
user = result;
|
||||
|
||||
if (user && !user.permission.disabled) {
|
||||
if (user.forceReset) {
|
||||
loginObject = {
|
||||
status: 200,
|
||||
authorized: false,
|
||||
err: {
|
||||
id: '003',
|
||||
code: '[UMAU003]',
|
||||
string: 'A password reset has been mandated. Please check your email for a password reset link or request a new one from the login screen.'
|
||||
}
|
||||
};
|
||||
resolve(loginObject);
|
||||
}
|
||||
else {
|
||||
try {
|
||||
Authentication.verifyPassword(login.password, Buffer.from(user.password, 'hex'), (err, valid) => {
|
||||
if (err) {
|
||||
console.log('[UserModel::authenticateUser] Error validating password', { err: err, user: user });
|
||||
reject(err);
|
||||
}
|
||||
|
||||
loginObject = {
|
||||
status: 200,
|
||||
authorized: valid
|
||||
};
|
||||
|
||||
if (valid) {
|
||||
loginObject.user = {
|
||||
_id: user._id,
|
||||
uid: user._id,
|
||||
userName: user.userName,
|
||||
name: user.name,
|
||||
title: user.title,
|
||||
email: user.email,
|
||||
permission: user.permission,
|
||||
settings: user.settings,
|
||||
avatar: user.avatar
|
||||
};
|
||||
|
||||
loginObject.timestamp = Date.now();
|
||||
|
||||
console.log('[UserModel::authenticateUser] User Validated', { user: user, loginObject: loginObject });
|
||||
resolve(loginObject);
|
||||
} else {
|
||||
loginObject.err = {
|
||||
id: '002',
|
||||
code: '[UMAU002]',
|
||||
string: 'The user id or password you entered was invalid.'
|
||||
};
|
||||
|
||||
console.log('[UserModel::authenticateUser] Invalid Password', { user: user, loginObject: loginObject });
|
||||
resolve(loginObject);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (err) {
|
||||
loginObject = {
|
||||
status: 200,
|
||||
authorized: false,
|
||||
err: {
|
||||
id: '004',
|
||||
code: '[UMAU004]',
|
||||
string: 'There was an error authenticating the user, please contact an administrator.'
|
||||
}
|
||||
};
|
||||
|
||||
console.log('[UserModel::authenticateUser] Error verifying password', { err: err, user: user });
|
||||
resolve(loginObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (user && user.permission.disabled) {
|
||||
loginObject = {
|
||||
status: 200,
|
||||
authorized: false,
|
||||
err: {
|
||||
id: '000',
|
||||
code: '[UMAU000]',
|
||||
string: 'The user is not authorized, please contact an administrator.'
|
||||
}
|
||||
};
|
||||
console.log('[UserModel::authenticateUser] The user is disabled', { err: err, user: user });
|
||||
resolve(loginObject);
|
||||
}
|
||||
else {
|
||||
loginObject = {
|
||||
status: 200,
|
||||
authorized: false,
|
||||
err: {
|
||||
id: '001',
|
||||
code: '[UMAU001]',
|
||||
string: 'The user id or password you entered was invalid.'
|
||||
}
|
||||
};
|
||||
console.log('[UserModel::authenticateUser] The user does not exist', { err: err, user: user });
|
||||
resolve(loginObject);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
promise.then((result) => {
|
||||
e.emit('authenticateUser', null, result);
|
||||
})
|
||||
.catch((err) => {
|
||||
e.emit('authenticateUser', err, null);
|
||||
});
|
||||
},
|
||||
|
||||
createUser: (e, user) => {
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
var userInstance = new UserModel(user);
|
||||
|
||||
userInstance.save((err, result) => {
|
||||
console.log('createUser', { err: err, result: result, user: userInstance });
|
||||
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
|
||||
if (result) {
|
||||
Reset.sendNewUser(null, result);
|
||||
resolve(result);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
promise.then((result) => {
|
||||
e.emit('createUser', null, result);
|
||||
})
|
||||
.catch((err) => {
|
||||
e.emit('createUser', err, null);
|
||||
});
|
||||
},
|
||||
|
||||
createUserGod: (e, user) => {
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
hashPassword(user.password, (err, hashedPassword) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
|
||||
if (hashedPassword) {
|
||||
user.password = hashedPassword;
|
||||
|
||||
var userInstance = new UserModel(user);
|
||||
|
||||
userInstance.save((err, result) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
|
||||
if (result) {
|
||||
resolve(result);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
promise.then((result) => {
|
||||
e.emit('createUserGod', null, result);
|
||||
})
|
||||
.catch((err) => {
|
||||
e.emit('createUserGod', err, null);
|
||||
});
|
||||
},
|
||||
|
||||
createUserSetting: (e, userId, data) => {
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
UserModel.findByIdAndUpdate(userId, { $push: { settings: data } }, (err, result) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
|
||||
if (result) {
|
||||
resolve(result);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
promise.then((result) => {
|
||||
e.emit('createUserSetting', null, result);
|
||||
})
|
||||
.catch((err) => {
|
||||
e.emit('createUserSetting', err, null);
|
||||
});
|
||||
},
|
||||
|
||||
deleteUser: (e, id) => {
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
UserModel.remove({ _id: id }, (err, result) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
|
||||
if (result) {
|
||||
resolve(result);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
promise.then((result) => {
|
||||
e.emit('deleteUser', null, result);
|
||||
})
|
||||
.catch((err) => {
|
||||
e.emit('deleteUser', err, null);
|
||||
});
|
||||
},
|
||||
|
||||
findUser: (query, callback) => {
|
||||
UserModel.findOne(query, (err, result) => {
|
||||
if (err) {
|
||||
callback(err, null);
|
||||
}
|
||||
|
||||
if (result) {
|
||||
callback(null, result);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
forcePasswordReset: (e, id) => {
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
UserModel.findByIdAndUpdate(id, { $set: { forceReset: true } }, { new: true }, (err, result) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
|
||||
if (result) {
|
||||
let resetPromise = new Promise((resetResolve, resetReject) => {
|
||||
Reset.forceReset(null, result, (result) => {
|
||||
if (result.success) {
|
||||
resetResolve({ success: true, message: 'Force password reset initiated on the user.', result: result });
|
||||
} else {
|
||||
resetResolve({ success: false, message: 'There was an error initiating the forced password reset.', result: result });
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
resetPromise.then((result) => {
|
||||
resolve(result);
|
||||
})
|
||||
.catch((err) => {
|
||||
reject(err);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
promise.then((result) => {
|
||||
e.emit('forcePasswordReset', null, result);
|
||||
})
|
||||
.catch((err) => {
|
||||
e.emit('forcePasswordReset', err, null);
|
||||
});
|
||||
},
|
||||
|
||||
getUsers: (e, query, restricted = true) => {
|
||||
query = query || { find: {}, options: { sort: { 'name.last': 1, 'name.first': 1 }, limit: 0, skip: 0 }};
|
||||
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
var projection = 'userName name' + (restricted ? '' : ' title email permission avatar settings forceReset');
|
||||
var query = UserModel.find(query.find, projection, query.options);
|
||||
|
||||
if (!restricted) {
|
||||
query.populate('permission', 'name disabled manageRoles manageUsers manageCategories manageAppPreferences deleteVendor addVendorTag addVendorSample addVendorComment editVendor addNewVendor viewPrivateDetails viewPublicDetails')
|
||||
}
|
||||
|
||||
query.exec((err, results) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
|
||||
if (results) {
|
||||
resolve(results);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
promise.then((results) => {
|
||||
if (e) {
|
||||
e.emit('getUsers', null, results);
|
||||
} else {
|
||||
return results;
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
if (e) {
|
||||
e.emit('getUsers', err, null);
|
||||
} else {
|
||||
return err;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
getUser: (e, id, restricted = true) => {
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
var projection = 'userName name' + (restricted ? '' : ' title email permission avatar settings forceReset');
|
||||
var query = UserModel
|
||||
.findById(id)
|
||||
.projection(projection);
|
||||
|
||||
if (!restricted) {
|
||||
query.populate('permission', 'name disabled manageRoles manageUsers manageCategories manageAppPreferences deleteVendor addVendorTag addVendorSample addVendorComment editVendor addNewVendor viewPrivateDetails viewPublicDetails');
|
||||
}
|
||||
|
||||
query.exec((err, result) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
|
||||
if (result) {
|
||||
resolve(result);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
promise.then((result) => {
|
||||
if (e) {
|
||||
e.emit('getUser', null, result);
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
if (e) {
|
||||
e.emit('getUser', err, null);
|
||||
} else {
|
||||
return err;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
getUserSetting: (e, id, key) => {
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
UserModel.findOne({ _id: id }, (err, result) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
|
||||
if (result) {
|
||||
for (let i = 0; i < result.settings.length; i ++) {
|
||||
if (result.settings[i].key === key) resolve(result.settings[i]);
|
||||
}
|
||||
|
||||
reject({ method: "getUserSetting", error: "The specified settings key does not exist" });
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
promise.then((result) => {
|
||||
e.emit('getUserSetting', null, result);
|
||||
})
|
||||
.catch((err) => {
|
||||
e.emit('getUserSetting', err, null);
|
||||
});
|
||||
},
|
||||
|
||||
getUserSettings: (e, id) => {
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
UserModel.findOne({_id: id}, (err, result) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
|
||||
if (result) {
|
||||
resolve(result.settings);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
promise.then((result) => {
|
||||
e.emit('getUserSettings', null, result);
|
||||
})
|
||||
.catch((err) => {
|
||||
e.emit('getUserSettings', err, null);
|
||||
});
|
||||
},
|
||||
|
||||
isUserNameUnique: (e, username) => {
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
UserModel.findOne({ userName: username }, (err, result) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
|
||||
if (result) {
|
||||
resolve({ unique: false, length: true });
|
||||
} else {
|
||||
resolve({ unique: true, length: true });
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
promise.then((result) => {
|
||||
e.emit('isUserNameUnique', null, result);
|
||||
})
|
||||
.catch((err) => {
|
||||
e.emit('isUserNameUnique', err, null);
|
||||
});
|
||||
},
|
||||
|
||||
updateUser: (e, id, user) => {
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
UserModel
|
||||
.findByIdAndUpdate(id, { $set: user }, { new: true })
|
||||
.populate('permission', 'name disabled manageRoles manageUsers manageCategories manageAppPreferences deleteVendor addVendorTag addVendorSample addVendorComment editVendor addNewVendor viewPrivateDetails viewPublicDetails')
|
||||
.exec((err, result) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
|
||||
if (result) {
|
||||
resolve(result);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
promise.then((result) => {
|
||||
e.emit('updateUser', null, result);
|
||||
})
|
||||
.catch((err) => {
|
||||
e.emit('updateUser', err, null);
|
||||
});
|
||||
},
|
||||
|
||||
updateUserByUserName: (e, username, user) => {
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
UserModel.update({ userName: username }, { $set: user }, { new: true }, (err, result) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
|
||||
if (result) {
|
||||
resolve(result);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
promise.then((result) => {
|
||||
e.emit('updateUserByUserName', null, result);
|
||||
})
|
||||
.catch((err) => {
|
||||
e.emit('updateUserByUserName', err, null);
|
||||
});
|
||||
},
|
||||
|
||||
updateUserSetting: (e, userId, settingsId, data) => {
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
var changed = {};
|
||||
|
||||
for (let property in data) {
|
||||
changed['settings.$.' + property] = data[property];
|
||||
}
|
||||
|
||||
UserModel.update({ _id: userId, 'settings._id': settingsId }, { $set: changed }, { new: true }, (err, result) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
|
||||
if (result) {
|
||||
resolve(result);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
promise.then((result) => {
|
||||
e.emit('updateUserSetting', null, result);
|
||||
})
|
||||
.catch((err) => {
|
||||
e.emit('updateUserSetting', err, null);
|
||||
});
|
||||
},
|
||||
|
||||
updatePassword: (e, id, token, data) => {
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
Reset.checkReset(null, id, token, (err, validatedId) => {
|
||||
if (data.userId === validatedId) {
|
||||
UserModel.findByIdAndUpdate(data.userId, { $set: { password: data.password, confirmPassword: data.confirmPassword, forceReset: false } }, { new: true }, (err, updated) => {
|
||||
if (err) {
|
||||
if (err.success === false) {
|
||||
resolve(err);
|
||||
} else {
|
||||
reject(err);
|
||||
}
|
||||
}
|
||||
|
||||
if (updated) {
|
||||
Reset.markUsed(null, id);
|
||||
resolve({ success: true, updated: updated });
|
||||
}
|
||||
});
|
||||
} else {
|
||||
resolve({ success: false, message: 'The password reset link is not valid. Please request a new link.'});
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
promise.then((result) => {
|
||||
e.emit('updatePassword', null, result);
|
||||
})
|
||||
.catch((err) => {
|
||||
e.emit('updatePassword', err, null);
|
||||
});
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user