agmission/Development/server/controllers/user.js

267 lines
8.6 KiB
JavaScript

'use strict';
const User = require('../model/user'),
UserModelFactory = require('../model/user_model_factory'),
App = require('../model/application'),
cache = require('../helpers/mem_cache'),
util = require('util'),
jwt = require('jsonwebtoken'),
verifyAsync = util.promisify(jwt.verify),
moment = require('moment'),
ObjectId = require('mongodb').ObjectId,
{ Errors, UserTypes, DEFAULT_LANG } = require('../helpers/constants'),
{ AppError, AppParamError } = require('../helpers/app_error'),
mailer = require('../helpers/mailer'),
env = require('../helpers/env'),
subscriptionCtl = require("./subscription");
async function ensureParentExists(user) {
if (!user || user.kind <= 1 || !user.parent || !ObjectId.isValid(user.parent)) return;
const pUser = await User.findById(ObjectId(user.parent), null, { lean: true });
if (!pUser) AppError.throw(Errors.PARENT_NOT_EXIST);
return pUser;
}
async function clearTempData(uid) {
if (ObjectId.isValid(uid))
await App.deleteMany({ byUser: ObjectId(uid), $or: [{ status: -1 }, { status: 0 }] });
}
async function createUser_post(req, res) {
const _user = req.body;
delete _user._id;
await ensureParentExists(_user);
const newUser = new User(_user);
const user = await newUser.save();
res.json(user);
}
async function getUser_get(req, res) {
const _user = await User.findById(req.params.userId, null, { lean: true }).populate({ path: 'Country', select: 'code name -_id' });
res.json(_user);
}
async function updateUser_put(req, res) {
const _user = req.body, userId = req.params.userId;
if (!_user || !ObjectId.isValid(userId)) AppParamError.throw();
delete req.body._id;
let kind = _user.kind;
if (!kind) {
const theUser = await User.findById(userId, 'kind', { lean: true });
if (!theUser) AppError.throw(Errors.USER_NOT_FOUND);
kind = theUser.kind;
}
const UserModel = UserModelFactory.create(kind);
const user = await UserModel.findOneAndUpdate({ _id: ObjectId(userId) }, _user, { new: true, lean: true });
res.json(user);
}
async function deleteUser(req, res) {
const _id = req.params.userId;
if (!_id || !ObjectId.isValid(_id)) AppParamError.throw();
const user = await User.findByIdAndRemove({ _id: ObjectId(_id) });
if (user) await user.remove();
cache.delete(_id);
res.json({ ok: true });
}
async function login_post(req, res) {
if (!req.body || !req.body.username || !req.body.password) AppError.throw(Errors.WRONG_CREDENTIAL);
const _options = { username: { $regex: new RegExp(`^${req.body.username}$`, 'i') }, password: req.body.password };
const _user = await User.findOne(_options, null, { lean: true });
if (!_user) AppError.throw(Errors.WRONG_CREDENTIAL);
if (_user.kind == UserTypes.DEVICE && (req.body.dev && req.body.dev == 'web')) AppError.throw(Errors.INVALID_ACCOUNT);
const hasParent = Boolean(_user && _user.parent && _user.kind >= 2);
// The applicator user
let _parentUser;
if (hasParent) {
_parentUser = await User.findOne({ _id: _user.parent }, null, { lean: true });
} else if (_user.kind === UserTypes.ADMIN || _user.kind === UserTypes.APP) {
_parentUser = _user;
}
if (hasParent && !_parentUser) AppError.throw(Errors.WRONG_CREDENTIAL);
await clearTempData(_user._id);
const isActive = hasParent ? (_parentUser.active && _user.active) : _user.active;
let authUser;
if (isActive) {
const premium = _parentUser.premium || 0; // To be removed soon
const token = jwt.sign({ uid: _user._id, ut: _user.kind }, env.TOKEN_SECRET, {});
const memberInfo = {};
// const memberInfo = _user.kind !== UserTypes.ADMIN ? await subscriptionCtl.resolvePaymentUser(_parentUser) : {};
let userLang = _user.lang; // #1518, Make sure only appy the language not it has not ever selected.
if (!userLang) {
const inUserLang = req.body.lang && req.body.lang.toLowerCase();
userLang = inUserLang && req.body.lang && ['en', 'pt', 'es'].includes(inUserLang) ? inUserLang : DEFAULT_LANG;
}
if (_user.kind === UserTypes.DEVICE) {
authUser = { token: token };
} else {
authUser = {
_id: _user._id, token: token, roles: [_user.kind], pui: _parentUser ? _parentUser._id : _user._id, lang: userLang, billable: _parentUser.billable, pre: premium, membership: memberInfo
};
}
// Update user last login info
await User.updateOne({ _id: _user._id }, { loggedInAt: Date.now(), lang: userLang }, { timestamps: false });
// Set the authenticated user info into the session cache
cache.set(_user._id.toHexString(), {
puid: _parentUser._id.toHexString(), billable: _parentUser.billable, premium: premium, membership: memberInfo, lang: userLang || DEFAULT_LANG, ts: moment.utc().unix(),
kind: _user.kind
});
} else {
AppError.throw(Errors.ACC_INACTIVE);
}
res.json(authUser);
}
async function isUserNameExists_post(req, res) {
if (!req.body || !req.body.username) AppParamError.throw();
const user = await User.findOne({ username: ({ $regex: new RegExp(`^${req.body.username}$`, 'i') }) });
res.json(user ? 1 : 0);
}
async function search_post(req, res) {
const _options = { markedDelete: { $ne: true } };
if (req.body.byPuid && ObjectId.isValid(req.body.byPuid))
_options.parent = ObjectId(req.body.byPuid);
else
AppParamError.throw();
if (req.body.kind)
_options.kind = req.body.kind;
else
_options.kind = { $in: [UserTypes.APP_ADM, UserTypes.OFFICER, UserTypes.INSPECTOR] };
const users = await User.find(_options, '-password').lean();
res.json(users || []);
}
async function clearTempData_post(req, res) {
await clearTempData(req.uid);
if (cache.get(req.uid))
cache.delete(req.uid);
res.json({ ok: true });
}
async function setUserLanguage_post(req, res) {
const lang = req.body.lang || DEFAULT_LANG;
const user = await User.findByIdAndUpdate(ObjectId(req.uid), { $set: { lang: String(lang).trim() } }, { new: true, lean: true });
// Update user language in the cache
const cUser = cache.get(req.uid);
if (cUser && cUser.lang && cUser.lang != user.lang) {
cUser.lang = user.lang;
cache.set(req.uid, cUser);
}
res.json(user);
}
async function getUserDetail_post(req, res) {
const uname = req.body.username;
if (!req.body || !uname) return res.json(null);
const user = await User.findOne({ username: { $regex: new RegExp(`^${uname}$`, 'i') } }, { password: 0 }).populate('parent', 'username').lean();
res.json(user);
}
function getHostFromReq(req) {
let host = `https://${req.hostname}`;
if (!req.app.isProd)
host += ':4200';
return host;
}
async function mailPwdReset_post(req, res) {
let userEmail = req.body.email;
if (!userEmail)
return res.json(null);
else
userEmail = userEmail.trim();
const user = await User.findOne({ username: userEmail });
if (!user) AppError.throw(Errors.USER_NOT_FOUND);
// Create the reset token to use within the reset password email link
const payload = { id: user._id, email: userEmail };
const secret = `${user.password}-${user.createdAt.getTime()}`;
const token = jwt.sign(payload, secret, { expiresIn: env.PWD_RESET_VALID_TIME || '3h' });
await mailer.sendMail(
'reset-password',
{
locale: user.lang || DEFAULT_LANG,
host: getHostFromReq(req), id: payload.id, token: token
},
userEmail
);
res.json({ result: 1 });
}
async function getResetPwdToken_get(req, res) {
if (!req.params || !req.params.id || !req.params.token) AppParamError.throw();
const user = await User.findOne({ _id: ObjectId(req.params.id) }).lean();
if (!user) AppError.throw(Errors.USER_NOT_FOUND);
const secret = `${user.password}-${user.createdAt.getTime()}`;
const verRes = await verifyAsync(req.params.token, secret);
res.json({ id: verRes.id, token: req.params.token });
}
async function resetPassword(req, res) {
if (!req.body.id) AppParamError.throw();
const user = await User.findOne({ _id: ObjectId(req.body.id) });
if (!user) AppError.throw(Errors.USER_NOT_FOUND);
const _user = user;
const secret = `${user.get('password')}-${user.get('createdAt').getTime()}`;
await jwt.verify(req.body.token, secret);
_user.password = req.body.password;
await _user.save();
await mailer.sendMail(
'password-reset',
{
locale: _user.lang || DEFAULT_LANG,
host: getHostFromReq(req), username: _user.username
},
_user.username,
);
res.json({ ok: true });
}
module.exports = {
isUserNameExists_post, createUser_post, getUser_get, updateUser_put, deleteUser, login_post, search_post, clearTempData_post, setUserLanguage_post,
getUserDetail_post, mailPwdReset_post, getResetPwdToken_get, resetPassword,
ensureParentExists, clearTempData, getHostFromReq
}