1188 lines
35 KiB
JavaScript
1188 lines
35 KiB
JavaScript
const User = require('../models/User');
|
|
const {body, validationResult} = require('express-validator');
|
|
const bcrypt = require('bcryptjs');
|
|
const jwt = require('jsonwebtoken');
|
|
const crypto = require('crypto');
|
|
const sharp = require('sharp');
|
|
const {secretKey} = require('./../authentication');
|
|
const {_sr} = require('../plugins/serverResponses');
|
|
const {res404, res500, hasWhiteSpaces, isLatinCharactersWithSymbol, generateRandomDigits} = require('../plugins/controllersHelperFunctions');
|
|
const fs = require('fs');
|
|
const nodemailer = require('nodemailer');
|
|
const Category = require('../models/Category');
|
|
const Logger = require('../models/Logger')
|
|
////// variables
|
|
const profileWidth = 500;
|
|
const profileHeight = 500;
|
|
const profileQuality = 100;
|
|
const hostURL = 'localhost:6688';
|
|
const limit = 20;
|
|
const select = '-password -token';
|
|
|
|
/** @todo add private to query */
|
|
|
|
/** auth --------------------------------------------- */
|
|
/////////////////////////////////////////////////////////////////////// login
|
|
module.exports.login = [
|
|
[
|
|
body('username')
|
|
.if((value, {req}) => {
|
|
return req.body.password && req.body.password.length >= 4
|
|
})
|
|
.custom((value, {req}) => {
|
|
var test = value;
|
|
return User.findOne({username: value})
|
|
.then(user => {
|
|
if (!user) return Promise.reject(_sr['fa'].not_found.password)
|
|
else return true
|
|
})
|
|
}),
|
|
|
|
body('password')
|
|
.notEmpty().withMessage(_sr['fa'].required.password)
|
|
.bail()
|
|
.isLength({min: 4}).withMessage(_sr['fa'].min_char.min4),
|
|
|
|
body('remember_me')
|
|
.exists().withMessage(_sr['fa'].required.remember_me)
|
|
.bail()
|
|
.isBoolean().withMessage(_sr['fa'].format.boolean)
|
|
],
|
|
async (req, res) => {
|
|
const errors = validationResult(req)
|
|
if (!errors.isEmpty()) return res.status(422).json({validation: errors.mapped()})
|
|
|
|
try {
|
|
var {username, password, remember_me} = req.body;
|
|
|
|
/** get user */
|
|
var user = await User.findOne({$or: [{username: username}, {email: username}]});
|
|
const logger = await Logger.findOne({user:user._id})
|
|
if (!user.registration_done) {
|
|
return res.status(403).json({message: `اکانت شما غیرفعال می باشد لطفا با ادمین تماس بگیرید`});
|
|
}
|
|
const isMatch = await bcrypt.compare(password,user.password)
|
|
|
|
/**check user */
|
|
if (user) {
|
|
/** check password */
|
|
|
|
if (isMatch) {
|
|
if(logger){
|
|
await Logger.findOneAndUpdate({user:user._id},{$set:{LastLogin:new Date()}},{new:true})
|
|
}else {
|
|
const newLogger = new Logger({
|
|
user:user,
|
|
LastLogin:new Date()
|
|
})
|
|
await newLogger.save();
|
|
}
|
|
/** if have token and it true show result else generate new token */
|
|
if (user.token) {
|
|
jwt.verify(user.token.replace(/^Bearer\s/, ''), secretKey, async (err, decoeded) => {
|
|
if (err || !decoeded) {
|
|
/** generate new token */
|
|
var token = await jwt.sign({_id: user._id}, secretKey, {expiresIn: remember_me ? '7d' : '1h'});
|
|
user.token = token;
|
|
await user.save();
|
|
return res.json({token: user.token});
|
|
} else {
|
|
return res.json({token: user.token});
|
|
}
|
|
});
|
|
} else {
|
|
/** generate new token */
|
|
var token = await jwt.sign({_id: user._id}, secretKey, {expiresIn: remember_me ? '7d' : '1h'});
|
|
user.token = token;
|
|
await user.save();
|
|
return res.json({token: user.token});
|
|
}
|
|
} else {
|
|
return res.status(422).json({validation: {username: {msg: _sr['fa'].not_found.password}}});
|
|
}
|
|
} else {
|
|
return res.status(422).json({validation: {username: {msg: _sr['fa'].not_found.password}}});
|
|
}
|
|
} catch (error) {
|
|
return res500(res, error?.message);
|
|
}
|
|
}
|
|
]
|
|
|
|
/////////////////////////////////////////////////////////////////////// logout
|
|
module.exports.logout = [
|
|
async (req, res) => {
|
|
const token = req.headers.authorization?.replace(/^Bearer\s/, '');
|
|
if (token) {
|
|
User.findOneAndUpdate({token: token}, {token: null}, (err, oldData) => {
|
|
if (err || !oldData) res.status(401).json({message: 'Your not logged in'})
|
|
else return res.json({message: 'You are logged out.'})
|
|
})
|
|
} else {
|
|
return res.status(401).json({message: 'Your not logged in'})
|
|
}
|
|
}
|
|
]
|
|
|
|
/////////////////////////////////////////////////////////////////////// get user
|
|
module.exports.getuser = [
|
|
async (req, res) => {
|
|
const token = req.headers.authorization?.replace(/^Bearer\s/, '');
|
|
// check if token is not destroyed
|
|
var user = await User.findOne({token: token}).select('-password');
|
|
|
|
if (!user) {
|
|
return res.status(401).json({message: 'unauthorized'});
|
|
}
|
|
|
|
if (!user.registration_done) {
|
|
return res.status(401).json({message: `اکانت شما غیرفعال می باشد لطفا با ادمین تماس بگیرید`});
|
|
}
|
|
|
|
//verifies secret and checks if the token is expired
|
|
try {
|
|
var checkToken = await jwt.verify(user.token.replace(/^Bearer\s/, ''), secretKey);
|
|
|
|
if (!checkToken) {
|
|
return res.status(401).json({message: 'unauthorized'});
|
|
}
|
|
|
|
return res.json({user: user});
|
|
} catch (error) {
|
|
return res.status(401).json({message: 'unauthorized'});
|
|
}
|
|
}
|
|
]
|
|
|
|
/** end auth --------------------------------------------- */
|
|
|
|
/////////////////////////////////////////////////////////////////////// admin
|
|
module.exports.registerAdmin = [
|
|
[
|
|
body('firstName')
|
|
.notEmpty().withMessage(_sr['fa'].required.first_name),
|
|
|
|
body('lastName')
|
|
.notEmpty().withMessage(_sr['fa'].required.last_name),
|
|
|
|
body('mobileNumber')
|
|
.if((value, {req}) => {
|
|
return req.body.mobileNumber
|
|
})
|
|
.custom((value, {req}) => {
|
|
if (!_.isEmpty(value) && !lodash.isNumeric(value)) {
|
|
return Promise.reject(_sr['fa'].format.number);
|
|
}
|
|
return User.findOne({mobileNumber: value})
|
|
.then(user => {
|
|
if (user) return Promise.reject(_sr['fa'].duplicated.phoneNumber);
|
|
else return true
|
|
})
|
|
}),
|
|
|
|
// body('email')
|
|
// .optional().isEmail().withMessage(_sr['fa'].format.email)
|
|
// .if((value, {req}) => {
|
|
// return req.body.email
|
|
// })
|
|
// .custom((value, {req}) => {
|
|
// return User.findOne({email: value})
|
|
// .then(user => {
|
|
// if (user) return Promise.reject(_sr['fa'].duplicated.email)
|
|
// else return true
|
|
// })
|
|
// }),
|
|
|
|
body('username')
|
|
.isLength({min: 4}).withMessage(_sr['fa'].min_char.min4)
|
|
.bail()
|
|
.custom((value, {req}) => {
|
|
if (hasWhiteSpaces(value)) return Promise.reject(_sr['fa'].response.whiteSpace)
|
|
else return true
|
|
})
|
|
.bail()
|
|
.custom((value, {req}) => {
|
|
if (!isLatinCharactersWithSymbol(value)) return Promise.reject(_sr['fa'].response.latinChar)
|
|
else return true
|
|
})
|
|
.bail()
|
|
.custom((value, {req}) => {
|
|
return User.findOne({username: value})
|
|
.then(user => {
|
|
if (user) return Promise.reject(_sr['fa'].duplicated.username)
|
|
else return true
|
|
})
|
|
}),
|
|
|
|
body('password')
|
|
.isLength({min: 4}).withMessage(_sr['fa'].min_char.min4)
|
|
.custom((value, {req}) => {
|
|
if (value === req.body.password_confirmation) return Promise.resolve()
|
|
else return Promise.reject(_sr['fa'].response.passwords_not_match)
|
|
}),
|
|
|
|
body('permissions')
|
|
.if((value, {req}) => {
|
|
return req.body.specialPermissions;
|
|
})
|
|
.custom((value, {req}) => {
|
|
var permission = _.isString(value) ? JSON.parse(value) : value;
|
|
if (!_.isArray(permission)) {
|
|
return Promise.reject(`این فیلد باید از نوع آرایه باشد`);
|
|
}
|
|
|
|
if (!permission.length) {
|
|
return Promise.reject(`شما باید یک دسترسی انتخاب کنید`);
|
|
}
|
|
|
|
if (permission.length && !permission.includes('superAdmin') && (!permission.includes('news') && !permission.includes('categories'))) {
|
|
return Promise.reject(`شما باید همراه با دسترسی مخصوص، دسترسی مدیریت صفحات یا اخبار را ارسال کنید`);
|
|
} else {
|
|
return true
|
|
}
|
|
}),
|
|
|
|
|
|
body('specialPermissions')
|
|
.optional()
|
|
.custom((value, {req}) => {
|
|
var specialPermissions = _.isString(value) && !_.isEmpty(value) ? JSON.parse(value) : value;
|
|
if (!_.isArray(specialPermissions)) {
|
|
return Promise.reject(`این فیلد باید از نوع آرایه باشد`);
|
|
}
|
|
|
|
return true
|
|
}),
|
|
|
|
body('portals')
|
|
.custom((value, {req}) => {
|
|
var portals = _.isString(value) ? JSON.parse(value) : value;
|
|
if (!_.isArray(portals)) {
|
|
return Promise.reject(`این فیلد باید از نوع آرایه باشد`);
|
|
}
|
|
|
|
if (!portals.length) {
|
|
return Promise.reject(`شما باید محدوده دسترسی را مشخص کنید`);
|
|
}
|
|
|
|
let isValid = portals.every((item) => {
|
|
return portal.includes(item);
|
|
});
|
|
|
|
if (isValid) {
|
|
return true;
|
|
} else {
|
|
return Promise.reject(`${_sr['fa'].optional.onlyValid} => ${portal}`);
|
|
}
|
|
}),
|
|
|
|
body('registration_done')
|
|
.isBoolean().withMessage(_sr['fa'].format.boolean),
|
|
],
|
|
async (req, res) => {
|
|
const errors = validationResult(req)
|
|
if (!errors.isEmpty()) return res.status(422).json({validation: errors.mapped()})
|
|
|
|
try {
|
|
var {
|
|
username,
|
|
password,
|
|
firstName,
|
|
lastName,
|
|
email,
|
|
mobileNumber,
|
|
permissions,
|
|
specialPermissions,
|
|
registration_done,
|
|
portals
|
|
} = req.body;
|
|
|
|
/** this code fix problem with array in form data */
|
|
permissions = _.isString(permissions) ? JSON.parse(permissions) : permissions;
|
|
specialPermissions = _.isString(specialPermissions) ? JSON.parse(specialPermissions) : specialPermissions;
|
|
portals = _.isString(portals) ? JSON.parse(portals) : portals;
|
|
|
|
var data = {
|
|
username,
|
|
firstName,
|
|
lastName,
|
|
email,
|
|
mobileNumber,
|
|
permissions,
|
|
registration_done,
|
|
private: false,
|
|
_creator: req.user?._id || null,
|
|
_updatedBy: req.user?._id || null,
|
|
specialPermissions: permissions.includes('superAdmin') ? [] : specialPermissions,
|
|
portals: [...new Set(portals)]
|
|
};
|
|
|
|
/**
|
|
* if we have pic upload to server
|
|
*/
|
|
if (req.files && req.files.profilePic) {
|
|
const image = req.files.profilePic;
|
|
if (!_sr.supportedImageFormats.includes(image.mimetype.split('/')[1])) {
|
|
return res.status(422).json({validation: {profilePic: {msg: _sr['fa'].format.image}}});
|
|
}
|
|
const imageName = 'user_' + Date.now() + '_' + username + '.' + image.mimetype.split('/')[1];
|
|
data.profilePic = imageName
|
|
try {
|
|
const target = sharp(image.data)
|
|
await target
|
|
.resize(profileWidth, profileHeight, {
|
|
fit: 'cover'
|
|
})
|
|
.jpeg({
|
|
quality: profileQuality
|
|
})
|
|
.toFile(`./static/uploads/images/users/${imageName}`)
|
|
} catch (e) {
|
|
return res500(res, e?.message)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* generate salt
|
|
*/
|
|
var salt = bcrypt.genSaltSync(10);
|
|
|
|
/**
|
|
* hash password with salt
|
|
*/
|
|
var hashPassword = bcrypt.hashSync(password, salt);
|
|
|
|
if (!hashPassword) {
|
|
return res500(res, `error in hash`);
|
|
}
|
|
|
|
data.password = hashPassword;
|
|
|
|
/**
|
|
* create new admin
|
|
*/
|
|
const newAdmin = await User.create(data);
|
|
|
|
/**
|
|
* if we have error show him
|
|
*/
|
|
if (!newAdmin) {
|
|
return res500(`error in register admin`);
|
|
}
|
|
|
|
/**
|
|
* show result
|
|
*/
|
|
return res.status(201).json({
|
|
message: _sr['fa'].response.success_save
|
|
})
|
|
|
|
} catch (error) {
|
|
return res500(res, error?.message);
|
|
}
|
|
}
|
|
]
|
|
|
|
/////////////////////////////////////////////////////////////////////// get user
|
|
module.exports.getUserByAdmin = [
|
|
async (req, res) => {
|
|
try {
|
|
const userId = req.params.id;
|
|
|
|
/** get one user */
|
|
const user = await User.findById(userId).populate('specialPermissions').select(select);
|
|
|
|
/** if not exist show message to client */
|
|
if (!user) {
|
|
return res404(res, `کاربر مورد نظر پیدا نشد`);
|
|
}
|
|
|
|
/** show result */
|
|
return res.json(user);
|
|
|
|
} catch (error) {
|
|
res500(res, error?.message);
|
|
}
|
|
}
|
|
]
|
|
|
|
/////////////////////////////////////////////////////////////////////// get all user
|
|
module.exports.getAllUsers = [
|
|
async (req, res) => {
|
|
try {
|
|
|
|
/** get all user */
|
|
const users = await User.paginate({private: false}, {page: req.query.page, limit, select});
|
|
|
|
/** if not exist show message to client */
|
|
if (!users) {
|
|
return res500(res, `مشکلی در گرفتن اطلاعات پیش آمده لطفا دوباره تلاش کنید`);
|
|
}
|
|
|
|
/** show result */
|
|
return res.json(users);
|
|
|
|
} catch (error) {
|
|
return res500(res, error?.message);
|
|
}
|
|
}
|
|
]
|
|
|
|
module.exports.changeUserStatus = [
|
|
async (req, res) => {
|
|
try {
|
|
|
|
const userId = req.params.id
|
|
|
|
let user = await User.findOne({private: false , _id : userId});
|
|
|
|
if (!user) {
|
|
return res404(res, `کاربر مورد نظر پیدا نشد`);
|
|
}
|
|
|
|
user.registration_done = !user.registration_done;
|
|
|
|
user.save();
|
|
|
|
/** show result */
|
|
return res.json(_sr['fa'].response.success_save);
|
|
|
|
} catch (error) {
|
|
return res500(res, `مشکلی در اجرای درخواست شما بوجود امده است`);
|
|
}
|
|
}
|
|
]
|
|
|
|
/////////////////////////////////////////////////////////////////////// delete one user
|
|
module.exports.deleteOneUser = [
|
|
async (req, res) => {
|
|
try {
|
|
const userId = req.params.id;
|
|
|
|
/** get one user */
|
|
const user = await User.findOne({_id: userId});
|
|
|
|
/** if not exist show message to client */
|
|
if (!user) {
|
|
return res404(res, `کاربر مورد نظر پیدا نشد`);
|
|
}
|
|
|
|
if (user.private) {
|
|
return res.status(403).json({message: `شما نمیتوانید این کاربر را حذف کنید`});
|
|
}
|
|
|
|
/**
|
|
* if exist old pic delete it from file
|
|
*/
|
|
if (user.profilePic) {
|
|
var oldPic = `./static${user.profilePic}`;
|
|
|
|
if (fs.existsSync(oldPic)) {
|
|
fs.unlink(oldPic, (err) => {
|
|
if (err) return res500(res, err?.message);
|
|
});
|
|
}
|
|
}
|
|
|
|
/** delete user */
|
|
await user.deleteOne();
|
|
|
|
/** show result */
|
|
return res.json(user);
|
|
|
|
} catch (error) {
|
|
res500(res, error?.message);
|
|
}
|
|
}
|
|
]
|
|
|
|
/////////////////////////////////////////////////////////////////////// update user
|
|
module.exports.updateUser = [
|
|
[
|
|
body('firstName')
|
|
.notEmpty().withMessage(_sr['fa'].required.first_name),
|
|
|
|
body('lastName')
|
|
.notEmpty().withMessage(_sr['fa'].required.last_name),
|
|
|
|
body('mobileNumber')
|
|
.if((value, {req}) => {
|
|
return req.body.mobileNumber
|
|
})
|
|
.custom((value, {req}) => {
|
|
if (!_.isEmpty(value) && !lodash.isNumeric(value)) {
|
|
return Promise.reject(_sr['fa'].format.number);
|
|
}
|
|
return true;
|
|
}),
|
|
|
|
// body('email')
|
|
// .optional().isEmail().withMessage(_sr['fa'].format.email),
|
|
|
|
body('permissions')
|
|
.if((value, {req}) => {
|
|
return req.body.specialPermissions;
|
|
})
|
|
.custom((value, {req}) => {
|
|
let permission = _.isString(value) ? JSON.parse(value) : value;
|
|
let specialPermissions = _.isString(req.body.specialPermissions) ? JSON.parse(req.body.specialPermissions) : req.body.specialPermissions;
|
|
if (!_.isArray(permission)) {
|
|
return Promise.reject(`این فیلد باید از نوع آرایه باشد`);
|
|
}
|
|
|
|
if (!permission.length) {
|
|
return Promise.reject(`شما باید یک دسترسی انتخاب کنید`);
|
|
}
|
|
|
|
if (specialPermissions.length !== 0 && !permission.includes('superAdmin') && (!permission.includes('news') && !permission.includes('categories'))) {
|
|
return Promise.reject(`شما باید همراه با دسترسی مخصوص، دسترسی مدیریت صفحات یا اخبار را ارسال کنید`);
|
|
} else {
|
|
return true
|
|
}
|
|
}),
|
|
|
|
|
|
body('specialPermissions')
|
|
.optional()
|
|
.custom((value, {req}) => {
|
|
var specialPermissions = _.isString(value) && !_.isEmpty(value) ? JSON.parse(value) : value;
|
|
if (!_.isArray(specialPermissions)) {
|
|
return Promise.reject(`این فیلد باید از نوع آرایه باشد`);
|
|
}
|
|
|
|
return true
|
|
}),
|
|
|
|
body('portals')
|
|
.custom((value, {req}) => {
|
|
var portals = _.isString(value) ? JSON.parse(value) : value;
|
|
if (!_.isArray(portals)) {
|
|
return Promise.reject(`این فیلد باید از نوع آرایه باشد`);
|
|
}
|
|
|
|
if (!portals.length) {
|
|
return Promise.reject(`شما باید محدوده دسترسی را مشخص کنید`);
|
|
}
|
|
|
|
let isValid = portals.every((item) => {
|
|
return portal.includes(item);
|
|
});
|
|
|
|
if (isValid) {
|
|
return true;
|
|
} else {
|
|
return Promise.reject(`${_sr['fa'].optional.onlyValid} => ${portal}`);
|
|
}
|
|
}),
|
|
|
|
body('registration_done')
|
|
.isBoolean().withMessage(_sr['fa'].format.boolean),
|
|
],
|
|
async (req, res) => {
|
|
const errors = validationResult(req)
|
|
if (!errors.isEmpty()) return res.status(422).json({validation: errors.mapped()})
|
|
|
|
try {
|
|
const userId = req.params.id;
|
|
|
|
var {
|
|
firstName,
|
|
lastName,
|
|
email,
|
|
mobileNumber,
|
|
permissions,
|
|
specialPermissions,
|
|
registration_done,
|
|
portals
|
|
} = req.body;
|
|
|
|
/** this code fix problem with array in form data */
|
|
permissions = _.isString(permissions) ? JSON.parse(permissions) : permissions;
|
|
specialPermissions = _.isString(specialPermissions) ? JSON.parse(specialPermissions) : specialPermissions;
|
|
portals = _.isString(portals) ? JSON.parse(portals) : portals;
|
|
|
|
/** get one user */
|
|
var user = await User.findById(userId);
|
|
|
|
/** if not exist show message to client */
|
|
if (!user) {
|
|
return res404(res, `کاربر مورد نظر پیدا نشد`);
|
|
}
|
|
|
|
if (!user.private && !req.user.private) {
|
|
return res.status(403).json({message: `شما نمیتوانید این کاربر را آپدیت کنید`});
|
|
}
|
|
|
|
/** check new email is dupllicate or not */
|
|
if (user.email !== email) {
|
|
var checkDupplicate = await User.find({email: email});
|
|
|
|
if (checkDupplicate.length) {
|
|
return res.status(422).json({validation: {email: {msg: `${_sr['fa'].duplicated.email}`}}});
|
|
}
|
|
}
|
|
/** check new mobileNumber is dupllicate or not */
|
|
if (user.mobileNumber !== mobileNumber) {
|
|
var checkDupplicate = await User.find({mobileNumber: mobileNumber});
|
|
|
|
if (checkDupplicate.length) {
|
|
return res.status(422).json({validation: {mobileNumber: {msg: `${_sr['fa'].duplicated.phoneNumber}`}}});
|
|
}
|
|
}
|
|
|
|
user.firstName = firstName;
|
|
user.lastName = lastName;
|
|
user.password = user.password;
|
|
user.scope = user.scope;
|
|
user.token = user.token;
|
|
user.mobileNumber = mobileNumber;
|
|
user.email = email;
|
|
user.registration_done = registration_done;
|
|
user._creator = req.user._id;
|
|
user.username = user.username;
|
|
user.permissions = permissions;
|
|
user.specialPermissions = permissions?.includes('superAdmin') ? [] : specialPermissions;
|
|
user.private = user.private;
|
|
user.portals = [...new Set(portals)]
|
|
|
|
if (req.files && req.files.profilePic) {
|
|
const image = req.files.profilePic;
|
|
if (!_sr.supportedImageFormats.includes(image.mimetype.split('/')[1])) {
|
|
return res.status(422).json({validation: {profilePic: {msg: _sr['fa'].format.image}}});
|
|
}
|
|
const imageName = 'user_' + Date.now() + '_' + user.username + '.' + image.mimetype.split('/')[1];
|
|
|
|
try {
|
|
const target = sharp(image.data)
|
|
await target
|
|
.resize(profileWidth, profileHeight, {
|
|
fit: 'cover'
|
|
})
|
|
.jpeg({
|
|
quality: profileQuality
|
|
})
|
|
.toFile(`./static/uploads/images/users/${imageName}`);
|
|
|
|
/**
|
|
* if exist old pic delete it from file
|
|
*/
|
|
if (user.profilePic) {
|
|
var oldPic = `./static${user.profilePic}`;
|
|
|
|
if (fs.existsSync(oldPic)) {
|
|
fs.unlink(oldPic, (err) => {
|
|
if (err) return res500(res, err?.message);
|
|
});
|
|
}
|
|
}
|
|
|
|
} catch (e) {
|
|
return res500(res, e?.message);
|
|
}
|
|
|
|
user.profilePic = imageName;
|
|
}
|
|
|
|
await user.save();
|
|
|
|
/** show result */
|
|
return res.json(user);
|
|
|
|
} catch (error) {
|
|
res500(res, error?.message);
|
|
}
|
|
}
|
|
]
|
|
|
|
/////////////////////////////////////////////////////////////////////// change password
|
|
module.exports.changePassword = [
|
|
[
|
|
body('password')
|
|
.isLength({min: 4}).withMessage(_sr['fa'].min_char.min4)
|
|
.custom((value, {req}) => {
|
|
if (value === req.body.password_confirmation) return Promise.resolve()
|
|
else return Promise.reject(_sr['fa'].response.passwords_not_match)
|
|
}),
|
|
],
|
|
async (req, res) => {
|
|
const errors = validationResult(req)
|
|
if (!errors.isEmpty()) return res.status(422).json({validation: errors.mapped()})
|
|
|
|
try {
|
|
const userId = req.params.id;
|
|
|
|
const password = req.body.password;
|
|
|
|
/** get one user */
|
|
var user = await User.findById(userId);
|
|
|
|
/** if not exist show message to client */
|
|
if (!user) {
|
|
return res404(res, `کاربر مورد نظر پیدا نشد`);
|
|
}
|
|
|
|
if (!user.private && !req.user.private) {
|
|
return res.status(403).json({message: `شما نمی توانید رمز عبور این کاربر را تغییر دهید`});
|
|
}
|
|
|
|
/**
|
|
* generate salt
|
|
*/
|
|
var salt = bcrypt.genSaltSync(10);
|
|
|
|
/**
|
|
* hash password with salt
|
|
*/
|
|
var hashPassword = bcrypt.hashSync(password, salt);
|
|
|
|
if (!hashPassword) {
|
|
return res500(res, `error in hash`);
|
|
}
|
|
|
|
user.password = hashPassword;
|
|
user.token = null
|
|
|
|
await user.save();
|
|
|
|
/** show result */
|
|
return res.json({message: _sr['fa'].response.success_save});
|
|
|
|
} catch (error) {
|
|
res500(res, error?.message);
|
|
}
|
|
}
|
|
]
|
|
|
|
/////////////////////////////////////////////////////////////////////// get profile(get self)
|
|
module.exports.getProfile = [
|
|
async (req, res) => {
|
|
try {
|
|
const userId = req.user._id;
|
|
|
|
/** get one user */
|
|
const user = await User.findById(userId).select(select);
|
|
|
|
/** if not exist show message to client */
|
|
if (!user) {
|
|
return res404(res, `کاربر مورد نظر پیدا نشد`);
|
|
}
|
|
|
|
/** show result */
|
|
return res.json(user);
|
|
|
|
} catch (error) {
|
|
res500(res, error?.message);
|
|
}
|
|
}
|
|
]
|
|
|
|
/////////////////////////////////////////////////////////////////////// update profile(get self)
|
|
module.exports.updateProfile = [
|
|
[
|
|
body('firstName')
|
|
.notEmpty().withMessage(_sr['fa'].required.first_name),
|
|
|
|
body('lastName')
|
|
.notEmpty().withMessage(_sr['fa'].required.last_name),
|
|
|
|
body('mobileNumber')
|
|
.isNumeric().withMessage(_sr['fa'].format.number),
|
|
|
|
// body('email')
|
|
// .isEmail().withMessage(_sr['fa'].format.email),
|
|
],
|
|
async (req, res) => {
|
|
const errors = validationResult(req)
|
|
if (!errors.isEmpty()) return res.status(422).json({validation: errors.mapped()})
|
|
|
|
try {
|
|
const userId = req.user._id;
|
|
|
|
const {
|
|
firstName,
|
|
lastName,
|
|
email,
|
|
mobileNumber,
|
|
} = req.body;
|
|
|
|
/** get one user */
|
|
var user = await User.findById(userId);
|
|
|
|
/** if not exist show message to client */
|
|
if (!user) {
|
|
return res404(res, `کاربر مورد نظر پیدا نشد`);
|
|
}
|
|
|
|
/** check new email is dupllicate or not */
|
|
if (user.email != email) {
|
|
var checkDupplicate = await User.find({email: email});
|
|
|
|
if (checkDupplicate.length) {
|
|
return res.status(422).json({validation: {email: {msg: `${_sr['fa'].duplicated.email}`}}});
|
|
}
|
|
}
|
|
/** check new mobileNumber is dupllicate or not */
|
|
if (user.mobileNumber != mobileNumber) {
|
|
var checkDupplicate = await User.find({mobileNumber: mobileNumber});
|
|
|
|
if (checkDupplicate.length) {
|
|
return res.status(422).json({validation: {mobileNumber: {msg: `${_sr['fa'].duplicated.phoneNumber}`}}});
|
|
}
|
|
}
|
|
|
|
user.firstName = firstName;
|
|
user.lastName = lastName;
|
|
user.password = user.password;
|
|
user.scope = user.scope;
|
|
user.token = user.token;
|
|
user.mobileNumber = mobileNumber;
|
|
user.email = email;
|
|
user.registration_done = user.registration_done;
|
|
user._creator = req.user._id;
|
|
user.username = user.username;
|
|
user.permissions = user.permissions;
|
|
user.specialPermissions = user.specialPermissions;
|
|
user.private = user.private;
|
|
|
|
/** if exist a picture */
|
|
if (req.files && req.files.profilePic) {
|
|
const image = req.files.profilePic;
|
|
if (!_sr.supportedImageFormats.includes(image.mimetype.split('/')[1])) {
|
|
return res.status(422).json({validation: {profilePic: {msg: _sr['fa'].format.image}}});
|
|
}
|
|
const imageName = 'user_' + Date.now() + '_' + user.username + '.' + image.mimetype.split('/')[1];
|
|
|
|
try {
|
|
const target = sharp(image.data)
|
|
await target
|
|
.resize(profileWidth, profileHeight, {
|
|
fit: 'cover'
|
|
})
|
|
.jpeg({
|
|
quality: profileQuality
|
|
})
|
|
.toFile(`./static/uploads/images/users/${imageName}`);
|
|
|
|
/**
|
|
* if exist old pic delete it from file
|
|
*/
|
|
if (user.profilePic) {
|
|
var oldPic = `./static${user.profilePic}`;
|
|
|
|
if (fs.existsSync(oldPic)) {
|
|
fs.unlink(oldPic, (err) => {
|
|
if (err) return res500(res, err?.message);
|
|
});
|
|
}
|
|
}
|
|
|
|
} catch (e) {
|
|
return res500(res, e?.message);
|
|
}
|
|
|
|
user.profilePic = imageName;
|
|
}
|
|
|
|
await user.save();
|
|
|
|
/** show result */
|
|
return res.json(user);
|
|
|
|
} catch (error) {
|
|
res500(res, error?.message);
|
|
}
|
|
}
|
|
]
|
|
|
|
/////////////////////////////////////////////////////////////////////// change password (profile)
|
|
module.exports.changePasswordProfile = [
|
|
[
|
|
body('password')
|
|
.isLength({min: 4}).withMessage(_sr['fa'].min_char.min4)
|
|
.custom((value, {req}) => {
|
|
if (value === req.body.password_confirmation) return Promise.resolve()
|
|
else return Promise.reject(_sr['fa'].response.passwords_not_match)
|
|
}),
|
|
],
|
|
async (req, res) => {
|
|
const errors = validationResult(req)
|
|
if (!errors.isEmpty()) return res.status(422).json({validation: errors.mapped()})
|
|
|
|
try {
|
|
const userId = req.user._id;
|
|
|
|
const password = req.body.password;
|
|
|
|
/** get one user */
|
|
var user = await User.findById(userId);
|
|
|
|
/** if not exist show message to client */
|
|
if (!user) {
|
|
return res404(res, `کاربر مورد نظر پیدا نشد`);
|
|
}
|
|
|
|
/**
|
|
* generate salt
|
|
*/
|
|
var salt = bcrypt.genSaltSync(10);
|
|
|
|
/**
|
|
* hash password with salt
|
|
*/
|
|
var hashPassword = bcrypt.hashSync(password, salt);
|
|
|
|
if (!hashPassword) {
|
|
return res500(res, `مشکلی در تغییر پسورد پیش آمده است`);
|
|
}
|
|
|
|
user.password = hashPassword;
|
|
user.token = null
|
|
|
|
await user.save();
|
|
|
|
/** show result */
|
|
return res.json({message: _sr['fa'].response.success_save});
|
|
|
|
} catch (error) {
|
|
res500(res, error?.message);
|
|
}
|
|
}
|
|
]
|
|
|
|
/////////////////////////////////////////////////////////////////////// forget password generate token
|
|
module.exports.forgetPassGenerateToken = [
|
|
[
|
|
body('email')
|
|
.optional().isEmail().withMessage(_sr['fa'].format.email)
|
|
.if((value, {req}) => {
|
|
return req.body.email
|
|
})
|
|
.custom((value, {req}) => {
|
|
return User.findOne({email: value})
|
|
.then(user => {
|
|
if (!user) return Promise.reject(_sr['fa'].not_found.email)
|
|
else return true
|
|
})
|
|
}),
|
|
],
|
|
async (req, res) => {
|
|
const errors = validationResult(req)
|
|
if (!errors.isEmpty()) return res.status(422).json({validation: errors.mapped()})
|
|
|
|
try {
|
|
const email = req.body.email;
|
|
|
|
/** get one user */
|
|
var user = await User.findOne({email: email});
|
|
|
|
/** if not exist show message to client */
|
|
if (!user) {
|
|
return res404(res, `کابر مورد نظر پیدا نشد`);
|
|
}
|
|
|
|
const token = crypto.randomBytes(20).toString('hex');
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
let transporter = nodemailer.createTransport({
|
|
host: "www.rubynaturalco.com",
|
|
port: 587,
|
|
secure: false, // true for 465, false for other ports
|
|
auth: {
|
|
user: 'recovery@rubynaturalco.com',
|
|
pass: 'jd-m2?3ao?b('
|
|
},
|
|
tls: {
|
|
rejectUnauthorized: false
|
|
}
|
|
})
|
|
|
|
const emailHTMLTemplate = `
|
|
<div style="direction: rtl;background-color: #065495;overflow: hidden;">
|
|
<div style="width: 50%;border-radius: 10px;margin: 150px auto;background: #fff;text-align: center;padding: 20px;box-shadow: 0 15px 30px #000;">
|
|
<H1 style="color: #000;">برای بازیابی کلمه عبور خود روی لینک زیر کلیک کنید.</H1>
|
|
<div style="text-align: center;margin-top: 20px;">
|
|
<a href="http://${hostURL}/auth/resetpass-newpass/${token}"
|
|
target="_blank"
|
|
style="display: inline-block;padding: 15px;background: #065495;color: #fff;border-radius: 5px;text-decoration: none;">بازیابی کلمه عبور</a>
|
|
</div>
|
|
</div>
|
|
<span style="opacity: 0">${Date.now()}</span>
|
|
</div>
|
|
`
|
|
|
|
// send mail with defined transport object
|
|
let info = await transporter.sendMail({
|
|
from: '"Ostandari Portal" <recovery@rubynaturalco.com>', // sender address
|
|
to: user.email, // list of receivers
|
|
subject: 'لینک بازیابی کلمه عبور',
|
|
text: 'کلمه عبور خود را بازیابی کنید',
|
|
html: emailHTMLTemplate
|
|
});
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
user.token = token;
|
|
|
|
|
|
await user.save();
|
|
|
|
/** show result */
|
|
return res.json(token);
|
|
|
|
} catch (error) {
|
|
res500(res, error?.message);
|
|
}
|
|
}
|
|
]
|
|
|
|
/////////////////////////////////////////////////////////////////////// forget password get token and change pass
|
|
module.exports.forgetPassGetToken = [
|
|
[
|
|
body('password')
|
|
.isLength({min: 4}).withMessage(_sr['fa'].min_char.min4)
|
|
.custom((value, {req}) => {
|
|
if (value === req.body.password_confirmation) return Promise.resolve()
|
|
else return Promise.reject(_sr['fa'].response.passwords_not_match)
|
|
}),
|
|
],
|
|
async (req, res) => {
|
|
const errors = validationResult(req)
|
|
if (!errors.isEmpty()) return res.status(422).json({validation: errors.mapped()});
|
|
|
|
try {
|
|
var token = req.params.token;
|
|
|
|
var password = req.body.password;
|
|
|
|
var user = await User.findOne({token: token});
|
|
|
|
if (!user) {
|
|
return res500(res, _sr['fa'].response.expired_reset_link); /** @todo change response */
|
|
}
|
|
|
|
/**
|
|
* generate salt
|
|
*/
|
|
var salt = bcrypt.genSaltSync(10);
|
|
|
|
/**
|
|
* hash password with salt
|
|
*/
|
|
var hashPassword = bcrypt.hashSync(password, salt);
|
|
|
|
if (!hashPassword) {
|
|
return res500(res, `مشکلی در تغییر رمز عبور پیش آمده است`); /** @todo change response */
|
|
}
|
|
|
|
user.password = hashPassword;
|
|
user.token = null;
|
|
|
|
await user.save();
|
|
|
|
/** show result */
|
|
return res.json({message: _sr['fa'].response.success_save});
|
|
|
|
} catch (error) {
|
|
res500(res, error?.message);
|
|
}
|
|
}
|
|
]
|
|
|
|
////////////////////////////////////////////////////////////////////// search
|
|
module.exports.search = [
|
|
async (req, res) => {
|
|
try {
|
|
var query = {private: false};
|
|
query['$and'] = [];
|
|
|
|
var {
|
|
name,
|
|
email,
|
|
phone,
|
|
permissions,
|
|
specialPermissions,
|
|
portals,
|
|
status,
|
|
username
|
|
} = req.body;
|
|
|
|
/** search by name and family */
|
|
if (name && !_.isEmpty(name)) {
|
|
query['$and'].push({
|
|
$or: [{
|
|
firstName: {
|
|
$regex: '.*' + name + '.*'
|
|
},
|
|
lastName: {
|
|
$regex: '.*' + name + '.*'
|
|
}
|
|
}]
|
|
});
|
|
}
|
|
/** search by email */
|
|
if (email && !_.isEmpty(email)) {
|
|
query['$and'].push({
|
|
email: email
|
|
});
|
|
}
|
|
/** search by phone */
|
|
if (phone && !_.isEmpty(phone)) {
|
|
query['$and'].push({
|
|
mobileNumber: phone
|
|
});
|
|
}
|
|
/** search by permissions */
|
|
if (permissions && !_.isEmpty(permissions)) {
|
|
query['$and'].push({
|
|
permissions: {
|
|
$in: permissions
|
|
}
|
|
});
|
|
}
|
|
/** search by specialPermissions */
|
|
if (specialPermissions && !_.isEmpty(specialPermissions)) {
|
|
query['$and'].push({
|
|
specialPermissions: {
|
|
$in: specialPermissions
|
|
}
|
|
});
|
|
}
|
|
/** search by portals */
|
|
if (portals && !_.isEmpty(portals)) {
|
|
query['$and'].push({
|
|
portals: {
|
|
$in: portals
|
|
}
|
|
})
|
|
}
|
|
/** search by status */
|
|
if (!_.isUndefined(status) && _.isBoolean(status)) {
|
|
query['$and'].push({
|
|
registration_done: status
|
|
})
|
|
}
|
|
/** search by username */
|
|
if (username && !_.isEmpty(username)) {
|
|
query['$and'].push({
|
|
username: username
|
|
});
|
|
}
|
|
|
|
_.isEmpty(query['$and']) && delete query['$and'];
|
|
// _.isEmpty(input['$or']) && delete input['$or'];
|
|
|
|
/** get users */
|
|
var users = await User.paginate(query, {page: req.query.page, limit, select});
|
|
|
|
/** show result */
|
|
return res.json(users);
|
|
} catch (error) {
|
|
return res500(res, error?.message);
|
|
}
|
|
}
|
|
]
|