1770 lines
55 KiB
JavaScript
1770 lines
55 KiB
JavaScript
const crypto = require('crypto')
|
|
const nodemailer = require('nodemailer')
|
|
const bcrypt = require('bcryptjs')
|
|
const { body, validationResult } = require('express-validator')
|
|
const jwt = require('jsonwebtoken')
|
|
const User = require('../models/User')
|
|
const { secretKey } = require('../authentication')
|
|
const permissions = require('../plugins/permissions')
|
|
const { _sr } = require('../plugins/serverResponses')
|
|
const { SMS } = require('../plugins/SMS_Module')
|
|
const { notifyAdmin } = require('../WebSocket/controllers/admin_EventsController')
|
|
const { saveUserToArpa, updateUserOnArpa } = require('../ArpaWebservice.js')
|
|
const {
|
|
res404,
|
|
res500,
|
|
checkValidations,
|
|
removeWhiteSpaces,
|
|
checkMobileNumber,
|
|
normalizeMobileNumber,
|
|
nameOptimizer,
|
|
checkNationalCode,
|
|
isPersian,
|
|
isPersianWithDigits,
|
|
generateRandomDigits
|
|
} = require('../plugins/controllersHelperFunctions')
|
|
const _faSr = _sr.fa
|
|
const transporter = nodemailer.createTransport({
|
|
host: 'smtp.c1.liara.email',
|
|
port: 587,
|
|
secure: false, // true for 465, false for other ports
|
|
auth: {
|
|
user: 'awesome_bell_ncc1hi',
|
|
pass: '509f8938-db95-4b8d-83e7-9ea8eccfd28b'
|
|
},
|
|
tls: {
|
|
rejectUnauthorized: false
|
|
}
|
|
})
|
|
/// ///////////////////////////////////////////////////////////////// verify account functions
|
|
function sendConfirmationEmail(userId) {
|
|
return new Promise(async (resolve, reject) => {
|
|
try {
|
|
const user = await User.findById(userId)
|
|
if (!user) throw new Error('invalid id')
|
|
|
|
const emailKey = generateRandomDigits(6)
|
|
user.emailConfirmationKey = emailKey
|
|
await user.save()
|
|
|
|
/// //// email configs
|
|
// const hostURL = 'www.asan-service.com'
|
|
|
|
|
|
const emailHTMLTemplate = `
|
|
<div style="direction: rtl;background-color: #065495;overflow: hidden;">
|
|
<div
|
|
style="width: 70%;border-radius: 10px;margin: 150px auto;background: #fff;text-align: center;padding: 20px;box-shadow: 0 15px 30px #000;"
|
|
>
|
|
<h1 style="color: #000;font-size: 25px;margin-bottom: 20px;">
|
|
<span> این ایمیل در وبسایت</span>
|
|
<strong style="color: #065495"> آسان سرویس </strong>
|
|
<span> ثبت شده است. </span>
|
|
</h1>
|
|
<p style="color: #000;">کد تایید آدرس ایمیل شما:</p>
|
|
<div style="text-align: center;margin-top: 5px;">
|
|
<p style="color: #065495;text-align: center;font-weight: bold;font-size: 20px;direction: ltr;">
|
|
${emailKey}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`
|
|
|
|
// send mail with defined transport object
|
|
await transporter.sendMail({
|
|
from: '"AsanService" <confirmation@asan-service.com>', // sender address
|
|
to: user.email, // list of receivers
|
|
subject: 'تایید ایمیل',
|
|
text: emailHTMLTemplate,
|
|
html: emailHTMLTemplate
|
|
})
|
|
|
|
resolve()
|
|
} catch (err) {
|
|
reject(err)
|
|
}
|
|
})
|
|
}
|
|
|
|
function sendConfirmationSMS(userId) {
|
|
return new Promise(async (resolve, reject) => {
|
|
try {
|
|
const user = await User.findById(userId)
|
|
if (!user) throw new Error('invalid id')
|
|
|
|
const mobileKey = generateRandomDigits(6)
|
|
user.mobileConfirmationKey = mobileKey
|
|
await user.save()
|
|
|
|
const smsMsg = [
|
|
'این شماره در وبسایت آسان سرویس جهت ارائه خدمات گارانتی ثبت گردیده.',
|
|
' کد تایید شماره همراه: ',
|
|
mobileKey
|
|
]
|
|
|
|
await SMS([user.mobile_number], smsMsg.join(''))
|
|
|
|
resolve()
|
|
} catch (err) {
|
|
reject(err)
|
|
}
|
|
})
|
|
}
|
|
|
|
/// //////////////////////////////////////////////////////////////////// admin accounts
|
|
module.exports.register_admin = [
|
|
[
|
|
body('first_name')
|
|
.notEmpty()
|
|
.withMessage(_faSr.required.first_name)
|
|
.bail()
|
|
.isLength({ min: 2 })
|
|
.withMessage(_faSr.min_char.min2),
|
|
|
|
body('last_name')
|
|
.notEmpty()
|
|
.withMessage(_faSr.required.last_name)
|
|
.bail()
|
|
.isLength({ min: 2 })
|
|
.withMessage(_faSr.min_char.min2),
|
|
|
|
body('username')
|
|
.notEmpty()
|
|
.withMessage(_faSr.required.username)
|
|
.bail()
|
|
.isLength({ min: 4 })
|
|
.withMessage(_faSr.min_char.min4)
|
|
.custom((value, { req }) => {
|
|
return User.findOne({ username: value }).then(admin => {
|
|
if (admin && admin.username === value) return Promise.reject(_faSr.duplicated.username)
|
|
else return true
|
|
})
|
|
}),
|
|
|
|
body('password')
|
|
.isLength({ min: 4 })
|
|
.withMessage(_faSr.min_char.min4)
|
|
.custom((value, { req }) => {
|
|
if (value === req.body.password_confirmation) return true
|
|
else return Promise.reject(_faSr.response.passwords_not_match)
|
|
})
|
|
],
|
|
checkValidations(validationResult),
|
|
async (req, res) => {
|
|
try {
|
|
const { first_name, last_name, username, permissions, personalCode } = req.body
|
|
|
|
const data = { first_name, last_name, username, permissions, personalCode }
|
|
data._creator = req.user_id
|
|
data.confirmed = true
|
|
data.scope = ['admin']
|
|
|
|
const salt = await bcrypt.genSalt(10)
|
|
const hash = await bcrypt.hash(req.body.password, salt)
|
|
data.password = hash
|
|
|
|
const admin = new User(data)
|
|
await admin.save()
|
|
return res.json({ message: _faSr.response.success_save })
|
|
} catch (err) {
|
|
return res500(res, err)
|
|
}
|
|
}
|
|
]
|
|
|
|
module.exports.update_admin = [
|
|
[
|
|
body('first_name')
|
|
.notEmpty()
|
|
.withMessage(_faSr.required.first_name)
|
|
.bail()
|
|
.isLength({ min: 2 })
|
|
.withMessage(_faSr.min_char.min2),
|
|
|
|
body('last_name')
|
|
.notEmpty()
|
|
.withMessage(_faSr.required.last_name)
|
|
.bail()
|
|
.isLength({ min: 2 })
|
|
.withMessage(_faSr.min_char.min2),
|
|
|
|
body('username')
|
|
.notEmpty()
|
|
.withMessage(_faSr.required.username)
|
|
.bail()
|
|
.isLength({ min: 4 })
|
|
.withMessage(_faSr.min_char.min4)
|
|
.custom((value, { req }) => {
|
|
return User.findOne({ username: value }).then(admin => {
|
|
if (admin && admin.username === value && admin._id.toString() !== req.params.id)
|
|
return Promise.reject(_faSr.duplicated.username)
|
|
else return true
|
|
})
|
|
})
|
|
],
|
|
checkValidations(validationResult),
|
|
(req, res) => {
|
|
const { username, first_name, last_name, permissions, personalCode } = req.body
|
|
|
|
const data = { username, first_name, last_name, permissions, personalCode }
|
|
data._creator = req.user_id
|
|
|
|
User.findByIdAndUpdate(req.params.id, data, (err, oldData) => {
|
|
if (err || !oldData) return res.status(404).json({ message: _faSr.not_found.user_id })
|
|
return res.json({ message: _faSr.response.success_activation })
|
|
})
|
|
}
|
|
]
|
|
|
|
module.exports.get_admins = [
|
|
(req, res) => {
|
|
const regex = /admin/
|
|
User.find({ scope: regex, private: false }, (err, admins) => {
|
|
if (err) return res500(res, err)
|
|
return res.json(admins)
|
|
})
|
|
}
|
|
]
|
|
|
|
module.exports.get_one_admin = [
|
|
(req, res) => {
|
|
User.findById(req.params.id)
|
|
.select('first_name last_name username permissions _creator personalCode')
|
|
.populate('_creator', 'first_name last_name')
|
|
.exec((err, admin) => {
|
|
if (err || !admin) return res.status(404).json({ message: _faSr.not_found.user_id })
|
|
else return res.json(admin)
|
|
})
|
|
}
|
|
]
|
|
|
|
module.exports.delete_admin = [
|
|
(req, res) => {
|
|
User.findByIdAndDelete(req.params.id, (err, user) => {
|
|
if (err || !user) return res.status(404).json({ message: _faSr.not_found.user_id })
|
|
else return res.json({ message: _faSr.response.success_save })
|
|
})
|
|
}
|
|
]
|
|
|
|
module.exports.permissions = [
|
|
(req, res) => {
|
|
return res.status(200).json(permissions)
|
|
}
|
|
]
|
|
|
|
/// //////////////////////////////////////////////////////////////////// user accounts
|
|
|
|
module.exports.register_user = [
|
|
[
|
|
body('first_name')
|
|
.notEmpty()
|
|
.withMessage(_faSr.required.first_name)
|
|
.bail()
|
|
.isLength({ min: 2 })
|
|
.withMessage(_faSr.min_char.min2)
|
|
.bail()
|
|
.custom((value, { req }) => {
|
|
if (removeWhiteSpaces(value).length < 2) return Promise.reject(_faSr.min_char.min2)
|
|
if (!isPersian(value)) return Promise.reject(new Error('لطفا با حروف فارسی تایپ کنید'))
|
|
else return true
|
|
}),
|
|
|
|
body('last_name')
|
|
.notEmpty()
|
|
.withMessage(_faSr.required.first_name)
|
|
.bail()
|
|
.isLength({ min: 2 })
|
|
.withMessage(_faSr.min_char.min2)
|
|
.bail()
|
|
.custom((value, { req }) => {
|
|
if (removeWhiteSpaces(value).length < 2) return Promise.reject(_faSr.min_char.min2)
|
|
if (!isPersian(value)) return Promise.reject(new Error('لطفا با حروف فارسی تایپ کنید'))
|
|
else return true
|
|
}),
|
|
|
|
body('national_code')
|
|
.notEmpty()
|
|
.withMessage(_faSr.required.national_code)
|
|
.bail()
|
|
.custom((value, { req }) => {
|
|
if (checkNationalCode(value)) return true
|
|
else return Promise.reject(_faSr.format.national_code)
|
|
})
|
|
.bail()
|
|
.custom((value, { req }) => {
|
|
const nationalCode = value.trim()
|
|
return User.findOne({ national_code: nationalCode }).then(user => {
|
|
if (user && user.national_code === nationalCode)
|
|
return Promise.reject(new Error('کاربر با این کد ملی از قبل وجود دارد'))
|
|
else return true
|
|
})
|
|
}),
|
|
|
|
body('province_id').notEmpty().withMessage(_faSr.required.province),
|
|
|
|
body('city_id').notEmpty().withMessage(_faSr.required.city),
|
|
|
|
body('address')
|
|
.notEmpty()
|
|
.withMessage(_faSr.required.address)
|
|
.bail()
|
|
.custom((value, { req }) => {
|
|
if (!isPersianWithDigits(value)) return Promise.reject(new Error('لطفا با حروف فارسی تایپ کنید'))
|
|
else return true
|
|
}),
|
|
|
|
body('postal_code')
|
|
.notEmpty()
|
|
.withMessage(_faSr.required.postal_code)
|
|
.bail()
|
|
.isNumeric()
|
|
.withMessage(_faSr.format.number),
|
|
|
|
body('email')
|
|
.notEmpty()
|
|
.withMessage(_faSr.required.email)
|
|
.bail()
|
|
.isEmail()
|
|
.withMessage(_faSr.format.email)
|
|
.bail()
|
|
.custom((value, { req }) => {
|
|
const email = value.trim().toLowerCase()
|
|
return User.findOne({ email }).then(user => {
|
|
if (user && user.email === email) return Promise.reject(_faSr.duplicated.email)
|
|
else return true
|
|
})
|
|
}),
|
|
|
|
body('tel_number')
|
|
.notEmpty()
|
|
.withMessage(_faSr.required.phone_number)
|
|
.bail()
|
|
.isNumeric()
|
|
.withMessage(_faSr.format.phone_number),
|
|
|
|
body('mobile_number')
|
|
.notEmpty()
|
|
.withMessage(_faSr.required.phone_number)
|
|
.bail()
|
|
.custom((value, { req }) => {
|
|
const mobileNStatus = checkMobileNumber(value)
|
|
if (!mobileNStatus) return Promise.reject(_faSr.format.phone_number)
|
|
else return Promise.resolve()
|
|
})
|
|
.bail()
|
|
.custom((value, { req }) => {
|
|
const mobileNumber = value.trim()
|
|
return User.findOne({ mobile_number: mobileNumber }).then(user => {
|
|
if (user && user.mobile_number === mobileNumber)
|
|
return Promise.reject(new Error('کاربر با این شماره موبایل از قبل وجود دارد'))
|
|
else return true
|
|
})
|
|
}),
|
|
|
|
body('password')
|
|
.isLength({ min: 4 })
|
|
.withMessage(_faSr.min_char.min4)
|
|
.custom((value, { req }) => {
|
|
if (value === req.body.password_confirmation) return true
|
|
else return Promise.reject(_faSr.response.passwords_not_match)
|
|
})
|
|
],
|
|
checkValidations(validationResult),
|
|
async (req, res) => {
|
|
try {
|
|
const {
|
|
first_name,
|
|
last_name,
|
|
national_code,
|
|
province_id,
|
|
province_name,
|
|
city_id,
|
|
city_name,
|
|
address,
|
|
postal_code,
|
|
tel_number,
|
|
mobile_number,
|
|
email,
|
|
store_name,
|
|
password
|
|
} = req.body
|
|
|
|
const data = {
|
|
last_name,
|
|
province_id,
|
|
province_name,
|
|
city_id,
|
|
city_name,
|
|
address,
|
|
postal_code,
|
|
tel_number,
|
|
store_name
|
|
}
|
|
data.first_name = nameOptimizer(first_name)
|
|
data.national_code = national_code.trim()
|
|
data.mobile_number = normalizeMobileNumber(mobile_number)
|
|
data.email = email.trim().toLowerCase()
|
|
|
|
// hash user password and done
|
|
const salt = await bcrypt.genSalt(10)
|
|
const hash = await bcrypt.hash(password, salt)
|
|
data.password = hash
|
|
|
|
const user = new User(data)
|
|
await user.save()
|
|
await sendConfirmationEmail(user._id)
|
|
await sendConfirmationSMS(user._id)
|
|
return res.json({ message: _faSr.response.success_save })
|
|
} catch (err) {
|
|
const registerFailurMsg = 'مشکلی در ثبت نام پیش آمده، لطفا مجددا تلاش کنید'
|
|
res500(res, registerFailurMsg)
|
|
}
|
|
}
|
|
]
|
|
|
|
module.exports.update_user = [
|
|
[
|
|
body('first_name')
|
|
.notEmpty()
|
|
.withMessage(_faSr.required.first_name)
|
|
.bail()
|
|
.isLength({ min: 2 })
|
|
.withMessage(_faSr.min_char.min2)
|
|
.bail()
|
|
.custom((value, { req }) => {
|
|
if (removeWhiteSpaces(value).length < 2) return Promise.reject(_faSr.min_char.min2)
|
|
if (!isPersian(value)) return Promise.reject(new Error('لطفا با حروف فارسی تایپ کنید'))
|
|
else return true
|
|
}),
|
|
|
|
body('last_name')
|
|
.notEmpty()
|
|
.withMessage(_faSr.required.first_name)
|
|
.bail()
|
|
.isLength({ min: 2 })
|
|
.withMessage(_faSr.min_char.min2)
|
|
.bail()
|
|
.custom((value, { req }) => {
|
|
if (removeWhiteSpaces(value).length < 2) return Promise.reject(_faSr.min_char.min2)
|
|
if (!isPersian(value)) return Promise.reject(new Error('لطفا با حروف فارسی تایپ کنید'))
|
|
else return true
|
|
}),
|
|
|
|
body('national_code')
|
|
.notEmpty()
|
|
.withMessage(_faSr.required.national_code)
|
|
.bail()
|
|
.custom((value, { req }) => {
|
|
if (checkNationalCode(value)) return true
|
|
else return Promise.reject(_faSr.format.national_code)
|
|
})
|
|
.custom((value, { req }) => {
|
|
const nationalCode = value.trim()
|
|
return User.findOne({ national_code: nationalCode }).then(user => {
|
|
if (user && user.national_code === nationalCode && user._id.toString() !== req.body._id)
|
|
return Promise.reject(new Error('کاربر با این کد ملی از قبل وجود دارد'))
|
|
else return true
|
|
})
|
|
}),
|
|
|
|
body('province_id').notEmpty().withMessage(_faSr.required.province),
|
|
|
|
body('city_id').notEmpty().withMessage(_faSr.required.city),
|
|
|
|
body('address')
|
|
.notEmpty()
|
|
.withMessage(_faSr.required.address)
|
|
.bail()
|
|
.custom((value, { req }) => {
|
|
if (!isPersianWithDigits(value)) return Promise.reject(new Error('لطفا با حروف فارسی تایپ کنید'))
|
|
else return true
|
|
}),
|
|
|
|
body('postal_code')
|
|
.notEmpty()
|
|
.withMessage(_faSr.required.postal_code)
|
|
.bail()
|
|
.isNumeric()
|
|
.withMessage(_faSr.format.number),
|
|
|
|
body('tel_number')
|
|
.notEmpty()
|
|
.withMessage(_faSr.required.phone_number)
|
|
.bail()
|
|
.isNumeric()
|
|
.withMessage(_faSr.format.phone_number),
|
|
|
|
body('mobile_number')
|
|
.notEmpty()
|
|
.withMessage(_faSr.required.phone_number)
|
|
.bail()
|
|
.custom((value, { req }) => {
|
|
const mobileNStatus = checkMobileNumber(value)
|
|
if (!mobileNStatus) return Promise.reject(_faSr.format.phone_number)
|
|
else return Promise.resolve()
|
|
})
|
|
.bail()
|
|
.custom((value, { req }) => {
|
|
const mobileNumber = value.trim()
|
|
return User.findOne({ mobile_number: mobileNumber }).then(user => {
|
|
if (user && user.mobile_number === mobileNumber && user._id.toString() !== req.body._id)
|
|
return Promise.reject(new Error('کاربر با این شماره موبایل از قبل وجود دارد'))
|
|
else return true
|
|
})
|
|
}),
|
|
|
|
body('email')
|
|
.notEmpty()
|
|
.withMessage(_faSr.required.email)
|
|
.bail()
|
|
.isEmail()
|
|
.withMessage(_faSr.format.email)
|
|
.bail()
|
|
.custom((value, { req }) => {
|
|
const email = value.trim().toLowerCase()
|
|
return User.findOne({ email }).then(user => {
|
|
if (user && user.email === email && user._id.toString() !== req.body._id)
|
|
return Promise.reject(_faSr.duplicated.email)
|
|
else return true
|
|
})
|
|
})
|
|
],
|
|
checkValidations(validationResult),
|
|
async (req, res) => {
|
|
const {
|
|
first_name,
|
|
last_name,
|
|
national_code,
|
|
province_id,
|
|
province_name,
|
|
city_id,
|
|
city_name,
|
|
address,
|
|
postal_code,
|
|
tel_number,
|
|
mobile_number,
|
|
email,
|
|
store_name
|
|
} = req.body
|
|
|
|
const MongoData = {
|
|
last_name,
|
|
province_id,
|
|
province_name,
|
|
city_id,
|
|
city_name,
|
|
address,
|
|
postal_code,
|
|
tel_number,
|
|
store_name
|
|
}
|
|
MongoData.first_name = nameOptimizer(first_name)
|
|
MongoData.national_code = national_code.trim()
|
|
MongoData.mobile_number = normalizeMobileNumber(mobile_number)
|
|
MongoData.email = email.trim().toLowerCase()
|
|
|
|
try {
|
|
const { user_id } = req
|
|
const user = await User.findById(user_id)
|
|
if (!user) return res404(res, _faSr.not_found.user_id)
|
|
|
|
const newEmail = user.email !== MongoData.email
|
|
const newMobile = user.mobile_number !== MongoData.mobile_number
|
|
if (newEmail) user.email_confirmed = false
|
|
if (newMobile) user.mobile_confirmed = false
|
|
|
|
await updateUserOnArpa(MongoData, user.verity_businessID, 'verity')
|
|
await updateUserOnArpa(MongoData, user.panatech_businessID, 'panatech')
|
|
|
|
user.first_name = MongoData.first_name
|
|
user.last_name = MongoData.last_name
|
|
user.national_code = MongoData.national_code
|
|
user.province_id = MongoData.province_id
|
|
user.province_name = MongoData.province_name
|
|
user.city_id = MongoData.city_id
|
|
user.city_name = MongoData.city_name
|
|
user.address = MongoData.address
|
|
user.postal_code = MongoData.postal_code
|
|
user.tel_number = MongoData.tel_number
|
|
user.store_name = MongoData.store_name
|
|
user.mobile_number = MongoData.mobile_number
|
|
user.email = MongoData.email
|
|
|
|
await user.save()
|
|
|
|
if (newEmail) await sendConfirmationEmail(user_id)
|
|
if (newMobile) await sendConfirmationSMS(user_id)
|
|
|
|
return res.json({ message: _faSr.response.success_save, data: user })
|
|
} catch (e) {
|
|
console.log('Arpa Error during update user --', e)
|
|
return res500(res, _faSr.response.problem)
|
|
}
|
|
}
|
|
]
|
|
|
|
module.exports.update_user_password = [
|
|
[
|
|
body('password')
|
|
.isLength({ min: 4 })
|
|
.withMessage(_faSr.min_char.min4)
|
|
.custom((value, { req }) => {
|
|
if (value === req.body.password_confirmation) return true
|
|
else return Promise.reject(_faSr.response.passwords_not_match)
|
|
})
|
|
],
|
|
checkValidations(validationResult),
|
|
async (req, res) => {
|
|
// hash user password and done
|
|
try {
|
|
const { _id, password } = req.body
|
|
const { user_id } = req
|
|
const salt = await bcrypt.genSalt(10)
|
|
const hash = await bcrypt.hash(password, salt)
|
|
const user = await User.findById(_id)
|
|
if (!user) throw new Error(_faSr.not_found.user_id)
|
|
user.password = hash
|
|
if (user.scope.includes('admin')) user._creator = user_id
|
|
await user.save()
|
|
return res.json({ message: _faSr.response.success_save })
|
|
} catch (err) {
|
|
if (err) return res500(res, err)
|
|
}
|
|
}
|
|
]
|
|
|
|
/// // reset user password
|
|
|
|
module.exports.generate_reset_user_password_link = [
|
|
[
|
|
body('type')
|
|
.notEmpty()
|
|
.withMessage('choose type')
|
|
.bail()
|
|
.custom((value, { req }) => {
|
|
if (value === 'email' || value === 'mobile') return Promise.resolve()
|
|
else return Promise.reject(new Error('invalid type'))
|
|
}),
|
|
|
|
body('email')
|
|
.if((value, { req }) => req.body.type === 'email')
|
|
.notEmpty()
|
|
.withMessage(_faSr.required.email)
|
|
.bail()
|
|
.isEmail()
|
|
.withMessage(_faSr.format.email),
|
|
|
|
body('mobile')
|
|
.if((value, { req }) => req.body.type === 'mobile')
|
|
.notEmpty()
|
|
.withMessage(_faSr.required.phone_number)
|
|
.bail()
|
|
.custom((value, { req }) => {
|
|
const mobileNStatus = checkMobileNumber(value)
|
|
if (!mobileNStatus) return Promise.reject(_faSr.format.phone_number)
|
|
else return Promise.resolve()
|
|
})
|
|
],
|
|
checkValidations(validationResult),
|
|
async (req, res) => {
|
|
try {
|
|
const { type, email, mobile } = req.body
|
|
const query = {}
|
|
if (type === 'email') query.email = email.toLowerCase().trim()
|
|
if (type === 'mobile') query.mobile_number = normalizeMobileNumber(mobile)
|
|
|
|
const user = await User.findOne(query)
|
|
if (!user) throw new Error('err')
|
|
|
|
const resetPassKey = await crypto.randomBytes(20).toString('hex')
|
|
user.resetPassToken = resetPassKey
|
|
const hostURL = 'www.asan-service.com'
|
|
|
|
if (type === 'email') {
|
|
|
|
|
|
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="https://${hostURL}/auth/resetpass-newpass/${resetPassKey}"
|
|
target="_blank"
|
|
style="display: inline-block;padding: 15px;background: #065495;color: #fff;border-radius: 5px;text-decoration: none;"
|
|
>بازیابی کلمه عبور</a
|
|
>
|
|
<p style="font-size: 10px;color: #b1b1b1;margin-top: 40px">
|
|
چنانچه قادر به کلیلک روی لینک بالا نیستید آدرس زیر را در مرورگر خود باز کنید.
|
|
</p>
|
|
<p style="font-size: 10px;color: #b1b1b1;">https://${hostURL}/auth/resetpass-newpass/${resetPassKey}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`
|
|
|
|
// send mail with defined transport object
|
|
await transporter.sendMail({
|
|
from: '"AsanService" <resetpassword@asan-service.com>', // sender address
|
|
to: email, // list of receivers
|
|
subject: 'لینک بازیابی کلمه عبور',
|
|
text: emailHTMLTemplate,
|
|
html: emailHTMLTemplate
|
|
})
|
|
} else {
|
|
const smsMsg = [
|
|
' لینک بازیابی کلمه عبور آسان سرویس: ',
|
|
`https://${hostURL}/auth/resetpass-newpass/${resetPassKey}`
|
|
]
|
|
await SMS([user.mobile_number], smsMsg.join(''))
|
|
}
|
|
|
|
await user.save()
|
|
let responseMsg = 'لینک بازیابی برای شما ارسال شد'
|
|
if (type === 'email')
|
|
responseMsg =
|
|
'لینک بازیابی برای شما ارسال شد، چنانچه قادر به مشاهده ایمیل در صندوق ورودی خود نیستید پوشه spam را چک کنید.'
|
|
return res.json({ message: responseMsg })
|
|
} catch (err) {
|
|
let errMsg = _faSr.not_found.user_id
|
|
if (err.code === 'EENVELOPE') errMsg = 'مشکلی در ارسال ایمیل پیش آمد لطفا دوباره تلاش کنید'
|
|
return res404(res, errMsg)
|
|
}
|
|
}
|
|
]
|
|
|
|
module.exports.reset_password_using_token = [
|
|
[
|
|
body('password')
|
|
.isLength({ min: 4 })
|
|
.withMessage(_faSr.min_char.min4)
|
|
.custom((value, { req }) => {
|
|
if (value === req.body.password_confirmation) return true
|
|
else return Promise.reject(_faSr.response.passwords_not_match)
|
|
})
|
|
],
|
|
checkValidations(validationResult),
|
|
async (req, res) => {
|
|
try {
|
|
const { token, password } = req.body
|
|
if (!token) throw new Error('err')
|
|
const user = await User.findOne({ resetPassToken: token })
|
|
if (!user) throw new Error('err')
|
|
const salt = await bcrypt.genSalt(10)
|
|
const hash = await bcrypt.hash(password, salt)
|
|
user.password = hash
|
|
user.token = null
|
|
user.resetPassToken = undefined
|
|
await user.save()
|
|
return res.json({ message: _faSr.response.success_save })
|
|
} catch (err) {
|
|
return res404(res, _faSr.response.expired_reset_link)
|
|
}
|
|
}
|
|
]
|
|
|
|
/// // confirm email
|
|
module.exports.changeEmail = [
|
|
[
|
|
body('email')
|
|
.notEmpty()
|
|
.withMessage(_faSr.required.email)
|
|
.bail()
|
|
.isEmail()
|
|
.withMessage(_faSr.format.email)
|
|
.bail()
|
|
.custom((value, { req }) => {
|
|
const email = value.toLowerCase()
|
|
return User.findOne({ email }).then(user => {
|
|
if (user && user.email === email) return Promise.reject(_faSr.duplicated.email)
|
|
else return true
|
|
})
|
|
})
|
|
],
|
|
checkValidations(validationResult),
|
|
async (req, res) => {
|
|
try {
|
|
const { user_id } = req
|
|
const { email } = req.body
|
|
const user = await User.findById(user_id)
|
|
if (!user) throw new Error('invalid id')
|
|
user.email = email
|
|
user.email_confirmed = false
|
|
await user.save()
|
|
await sendConfirmationEmail(user_id)
|
|
return res.json({ message: 'کد تایید برای شما ارسال شد' })
|
|
} catch (err) {
|
|
return res500(res, err)
|
|
}
|
|
}
|
|
]
|
|
|
|
module.exports.resendEmailConfirmation = [
|
|
async (req, res) => {
|
|
try {
|
|
const { user_id } = req
|
|
await sendConfirmationEmail(user_id)
|
|
return res.json({ message: 'کد تایید برای شما ارسال شد' })
|
|
} catch (err) {
|
|
return res500(res, err)
|
|
}
|
|
}
|
|
]
|
|
|
|
module.exports.confirmEmail = [
|
|
async (req, res) => {
|
|
try {
|
|
const { user_id } = req
|
|
const { verificationKey } = req.body
|
|
const user = await User.findById(user_id)
|
|
if (!user) throw new Error('err')
|
|
|
|
if (verificationKey?.trim() !== user.emailConfirmationKey) throw new Error('404')
|
|
|
|
if (!user.confirmed) {
|
|
user.confirmed = true
|
|
|
|
const verityID = await saveUserToArpa(user, 'verity')
|
|
const panatechID = await saveUserToArpa(user, 'panatech')
|
|
|
|
user.verity_businessID = verityID.businessID
|
|
user.verity_businessCode = verityID.businessCode
|
|
|
|
user.panatech_businessID = panatechID.businessID
|
|
user.panatech_businessCode = panatechID.businessCode
|
|
}
|
|
|
|
// save new info to arpa
|
|
await updateUserOnArpa(user, user.verity_businessID, 'verity')
|
|
await updateUserOnArpa(user, user.panatech_businessID, 'panatech')
|
|
|
|
// update user info in mongoDB
|
|
user.email_confirmed = true
|
|
user.emailConfirmationKey = undefined
|
|
await user.save()
|
|
|
|
return res.json({ message: 'ایمل شما تایید شد.' })
|
|
} catch (e) {
|
|
if (e === '404') return res404(res, 'کد تایید صحیح نمیباشد.')
|
|
else return res500(res, 'مشکلی در تایید ایمیل پیش آمده، لطفا دوباره تلاش کنید')
|
|
}
|
|
}
|
|
]
|
|
|
|
/// // confirm mobile
|
|
module.exports.changeMobile = [
|
|
[
|
|
body('mobile')
|
|
.notEmpty()
|
|
.withMessage(_faSr.required.phone_number)
|
|
.bail()
|
|
.custom((value, { req }) => {
|
|
const mobileNStatus = checkMobileNumber(value)
|
|
if (!mobileNStatus) return Promise.reject(_faSr.format.phone_number)
|
|
else return Promise.resolve()
|
|
})
|
|
.bail()
|
|
.custom((value, { req }) => {
|
|
return User.findOne({ mobile_number: value }).then(user => {
|
|
if (user && user.mobile_number === value)
|
|
return Promise.reject(new Error('کاربر با این شماره موبایل از قبل وجود دارد'))
|
|
else return true
|
|
})
|
|
})
|
|
],
|
|
checkValidations(validationResult),
|
|
async (req, res) => {
|
|
try {
|
|
const { user_id } = req
|
|
const { mobile } = req.body
|
|
const user = await User.findById(user_id)
|
|
if (!user) throw new Error('invalid id')
|
|
user.mobile_number = mobile
|
|
user.mobile_confirmed = false
|
|
await user.save()
|
|
await sendConfirmationSMS(user_id)
|
|
return res.json({ message: 'کد تایید برای شما پیامک شد' })
|
|
} catch (err) {
|
|
return res500(res, err)
|
|
}
|
|
}
|
|
]
|
|
|
|
module.exports.resendMobileConfirmation = [
|
|
async (req, res) => {
|
|
try {
|
|
const { user_id } = req
|
|
await sendConfirmationSMS(user_id)
|
|
return res.json({ message: 'کد تایید برای شما پیامک شد' })
|
|
} catch (err) {
|
|
return res500(res, err)
|
|
}
|
|
}
|
|
]
|
|
|
|
module.exports.confirmMobile = [
|
|
async (req, res) => {
|
|
try {
|
|
const { user_id } = req
|
|
const { verificationKey } = req.body
|
|
const user = await User.findById(user_id)
|
|
if (!user) throw new Error('err')
|
|
|
|
if (verificationKey?.trim() !== user.mobileConfirmationKey) throw new Error('404')
|
|
|
|
if (!user.confirmed) {
|
|
user.confirmed = true
|
|
|
|
const verityID = await saveUserToArpa(user, 'verity')
|
|
const panatechID = await saveUserToArpa(user, 'panatech')
|
|
|
|
user.verity_businessID = verityID.businessID
|
|
user.verity_businessCode = verityID.businessCode
|
|
|
|
user.panatech_businessID = panatechID.businessID
|
|
user.panatech_businessCode = panatechID.businessCode
|
|
}
|
|
|
|
// save new info to arpa
|
|
await updateUserOnArpa(user, user.verity_businessID, 'verity')
|
|
await updateUserOnArpa(user, user.panatech_businessID, 'panatech')
|
|
|
|
// update user info in mongoDB
|
|
user.mobile_confirmed = true
|
|
user.mobileConfirmationKey = undefined
|
|
await user.save()
|
|
|
|
return res.json({ message: 'شماره شما تایید شد.' })
|
|
} catch (e) {
|
|
if (e === '404') return res404(res, 'کد تایید صحیح نمیباشد.')
|
|
else return res500(res, 'مشکلی در تایید شماره پیش آمده، لطفا دوباره تلاش کنید')
|
|
}
|
|
}
|
|
]
|
|
|
|
/// //////////////////////////////////////////////////////////////////// user managemnet by admin
|
|
|
|
module.exports.add_user = [
|
|
[
|
|
body('first_name')
|
|
.notEmpty()
|
|
.withMessage(_faSr.required.first_name)
|
|
.bail()
|
|
.isLength({ min: 2 })
|
|
.withMessage(_faSr.min_char.min2)
|
|
.bail()
|
|
.custom((value, { req }) => {
|
|
if (removeWhiteSpaces(value).length < 2) return Promise.reject(_faSr.min_char.min2)
|
|
if (!isPersian(value)) return Promise.reject(new Error('لطفا با حروف فارسی تایپ کنید'))
|
|
else return true
|
|
}),
|
|
|
|
body('last_name')
|
|
.notEmpty()
|
|
.withMessage(_faSr.required.first_name)
|
|
.bail()
|
|
.isLength({ min: 2 })
|
|
.withMessage(_faSr.min_char.min2)
|
|
.bail()
|
|
.custom((value, { req }) => {
|
|
if (removeWhiteSpaces(value).length < 2) return Promise.reject(_faSr.min_char.min2)
|
|
if (!isPersian(value)) return Promise.reject(new Error('لطفا با حروف فارسی تایپ کنید'))
|
|
else return true
|
|
}),
|
|
|
|
body('national_code')
|
|
.notEmpty()
|
|
.withMessage(_faSr.required.national_code)
|
|
.bail()
|
|
.custom((value, { req }) => {
|
|
if (checkNationalCode(value)) return true
|
|
else return Promise.reject(_faSr.format.national_code)
|
|
})
|
|
.bail()
|
|
.custom((value, { req }) => {
|
|
const nationalCode = value.trim()
|
|
return User.findOne({ national_code: nationalCode }).then(user => {
|
|
if (user && user.national_code === nationalCode)
|
|
return Promise.reject(new Error('کاربر با این کد ملی از قبل وجود دارد'))
|
|
else return true
|
|
})
|
|
}),
|
|
|
|
body('province_id').notEmpty().withMessage(_faSr.required.province),
|
|
|
|
body('city_id').notEmpty().withMessage(_faSr.required.city),
|
|
|
|
body('address')
|
|
.notEmpty()
|
|
.withMessage(_faSr.required.address)
|
|
.bail()
|
|
.custom((value, { req }) => {
|
|
if (!isPersianWithDigits(value)) return Promise.reject(new Error('لطفا با حروف فارسی تایپ کنید'))
|
|
else return true
|
|
}),
|
|
|
|
body('postal_code')
|
|
.notEmpty()
|
|
.withMessage(_faSr.required.postal_code)
|
|
.bail()
|
|
.isNumeric()
|
|
.withMessage(_faSr.format.number),
|
|
|
|
body('email')
|
|
.notEmpty()
|
|
.withMessage(_faSr.required.email)
|
|
.bail()
|
|
.isEmail()
|
|
.withMessage(_faSr.format.email)
|
|
.bail()
|
|
.custom((value, { req }) => {
|
|
const email = value.trim().toLowerCase()
|
|
return User.findOne({ email }).then(user => {
|
|
if (user && user.email === email) return Promise.reject(_faSr.duplicated.email)
|
|
else return true
|
|
})
|
|
}),
|
|
|
|
body('tel_number')
|
|
.notEmpty()
|
|
.withMessage(_faSr.required.phone_number)
|
|
.bail()
|
|
.isNumeric()
|
|
.withMessage(_faSr.format.phone_number),
|
|
|
|
body('mobile_number')
|
|
.notEmpty()
|
|
.withMessage(_faSr.required.phone_number)
|
|
.bail()
|
|
.custom((value, { req }) => {
|
|
const mobileNStatus = checkMobileNumber(value)
|
|
if (!mobileNStatus) return Promise.reject(_faSr.format.phone_number)
|
|
else return Promise.resolve()
|
|
})
|
|
.bail()
|
|
.custom((value, { req }) => {
|
|
const mobileNumber = value.trim()
|
|
return User.findOne({ mobile_number: mobileNumber }).then(user => {
|
|
if (user && user.mobile_number === mobileNumber)
|
|
return Promise.reject(new Error('کاربر با این شماره موبایل از قبل وجود دارد'))
|
|
else return true
|
|
})
|
|
}),
|
|
|
|
body('password')
|
|
.isLength({ min: 4 })
|
|
.withMessage(_faSr.min_char.min4)
|
|
.custom((value, { req }) => {
|
|
if (value === req.body.password_confirmation) return true
|
|
else return Promise.reject(_faSr.response.passwords_not_match)
|
|
})
|
|
],
|
|
checkValidations(validationResult),
|
|
async (req, res) => {
|
|
try {
|
|
const {
|
|
first_name,
|
|
last_name,
|
|
national_code,
|
|
province_id,
|
|
province_name,
|
|
city_id,
|
|
city_name,
|
|
address,
|
|
postal_code,
|
|
tel_number,
|
|
mobile_number,
|
|
email,
|
|
store_name,
|
|
password
|
|
} = req.body
|
|
|
|
const data = {
|
|
last_name,
|
|
province_id,
|
|
province_name,
|
|
city_id,
|
|
city_name,
|
|
address,
|
|
postal_code,
|
|
tel_number,
|
|
store_name
|
|
}
|
|
data.first_name = nameOptimizer(first_name)
|
|
data.national_code = national_code.trim()
|
|
data.mobile_number = normalizeMobileNumber(mobile_number)
|
|
data.email = email.trim().toLowerCase()
|
|
data.email_confirmed = true
|
|
data.mobile_confirmed = true
|
|
data.confirmed = true
|
|
|
|
// hash user password and done
|
|
const salt = await bcrypt.genSalt(10)
|
|
const hash = await bcrypt.hash(password, salt)
|
|
data.password = hash
|
|
|
|
const user = new User(data)
|
|
await user.save()
|
|
|
|
const verityID = await saveUserToArpa(user, 'verity')
|
|
const panatechID = await saveUserToArpa(user, 'panatech')
|
|
|
|
user.verity_businessID = verityID.businessID
|
|
user.verity_businessCode = verityID.businessCode
|
|
|
|
user.panatech_businessID = panatechID.businessID
|
|
user.panatech_businessCode = panatechID.businessCode
|
|
|
|
|
|
// save new info to arpa
|
|
await updateUserOnArpa(user, user.verity_businessID, 'verity')
|
|
await updateUserOnArpa(user, user.panatech_businessID, 'panatech')
|
|
await user.save()
|
|
|
|
return res.status(200).json({ message: _faSr.response.success_save, user })
|
|
} catch (err) {
|
|
const registerFailurMsg = 'مشکلی در ثبت نام پیش آمده، لطفا مجددا تلاش کنید'
|
|
res500(res, registerFailurMsg)
|
|
}
|
|
}
|
|
]
|
|
|
|
module.exports.get_all_users_for_admin = [
|
|
(req, res) => {
|
|
User.find(
|
|
{
|
|
scope: ['user'],
|
|
confirmed: true,
|
|
verity_businessID: { $ne: null },
|
|
verity_businessCode: { $ne: null }
|
|
},
|
|
(err, data) => {
|
|
if (err) return res500(res, err)
|
|
return res.status(200).json(data)
|
|
}
|
|
)
|
|
}
|
|
]
|
|
|
|
module.exports.get_one_user_for_admin = [
|
|
(req, res) => {
|
|
User.findById(req.params.id, (err, user) => {
|
|
if (err || !user) return res404(res, err)
|
|
if (!user.seenByAdmin) {
|
|
user.seenByAdmin = true
|
|
user.save(err => {
|
|
if (err) console.log('get one user for admin - save seenByAdmin error :', err)
|
|
notifyAdmin('updateNewCustomers')
|
|
})
|
|
}
|
|
return res.json(user)
|
|
})
|
|
}
|
|
]
|
|
|
|
module.exports.change_verity_info_by_admin = [
|
|
[
|
|
body('verity_businessCode').notEmpty().withMessage('کد مشتری نباید خالی باشد'),
|
|
|
|
body('verity_businessID').notEmpty().withMessage('آیدی مشتری نباید خالی باشد')
|
|
],
|
|
checkValidations(validationResult),
|
|
async (req, res) => {
|
|
try {
|
|
const user = await User.findById(req.params?.id)
|
|
if (!user) return res404(res, 'invalid user id')
|
|
if (!user.old_verity_businessID && !user.old_verity_businessCode) {
|
|
user.old_verity_businessID = user.verity_businessID
|
|
user.old_verity_businessCode = user.verity_businessCode
|
|
await user.save()
|
|
}
|
|
user.verity_businessID = req.body.verity_businessID
|
|
user.verity_businessCode = req.body.verity_businessCode
|
|
await user.save()
|
|
return res.json({ message: _faSr.response.success_save })
|
|
} catch (err) {
|
|
return res500(res, err)
|
|
}
|
|
}
|
|
]
|
|
|
|
module.exports.change_panatech_info_by_admin = [
|
|
[
|
|
body('panatech_businessCode').notEmpty().withMessage('کد مشتری نباید خالی باشد'),
|
|
|
|
body('panatech_businessID').notEmpty().withMessage('آیدی مشتری نباید خالی باشد')
|
|
],
|
|
checkValidations(validationResult),
|
|
async (req, res) => {
|
|
try {
|
|
const user = await User.findById(req.params?.id)
|
|
if (!user) return res404(res, 'invalid user id')
|
|
if (!user.old_panatech_businessID && !user.old_panatech_businessCode) {
|
|
user.old_panatech_businessID = user.panatech_businessID
|
|
user.old_panatech_businessCode = user.panatech_businessCode
|
|
await user.save()
|
|
}
|
|
user.panatech_businessID = req.body.panatech_businessID
|
|
user.panatech_businessCode = req.body.panatech_businessCode
|
|
await user.save()
|
|
return res.json({ message: _faSr.response.success_save })
|
|
} catch (err) {
|
|
return res500(res, err)
|
|
}
|
|
}
|
|
]
|
|
|
|
|
|
module.exports.update_user_by_admin = [
|
|
[
|
|
body('first_name')
|
|
.notEmpty()
|
|
.withMessage(_faSr.required.first_name)
|
|
.bail()
|
|
.isLength({ min: 2 })
|
|
.withMessage(_faSr.min_char.min2)
|
|
.bail()
|
|
.custom((value, { req }) => {
|
|
if (removeWhiteSpaces(value).length < 2) return Promise.reject(_faSr.min_char.min2)
|
|
if (!isPersian(value)) return Promise.reject(new Error('لطفا با حروف فارسی تایپ کنید'))
|
|
else return true
|
|
}),
|
|
|
|
body('last_name')
|
|
.notEmpty()
|
|
.withMessage(_faSr.required.first_name)
|
|
.bail()
|
|
.isLength({ min: 2 })
|
|
.withMessage(_faSr.min_char.min2)
|
|
.bail()
|
|
.custom((value, { req }) => {
|
|
if (removeWhiteSpaces(value).length < 2) return Promise.reject(_faSr.min_char.min2)
|
|
if (!isPersian(value)) return Promise.reject(new Error('لطفا با حروف فارسی تایپ کنید'))
|
|
else return true
|
|
}),
|
|
|
|
body('national_code')
|
|
.notEmpty()
|
|
.withMessage(_faSr.required.national_code)
|
|
.bail()
|
|
.custom((value, { req }) => {
|
|
if (checkNationalCode(value)) return true
|
|
else return Promise.reject(_faSr.format.national_code)
|
|
})
|
|
.custom((value, { req }) => {
|
|
const nationalCode = value.trim()
|
|
return User.findOne({ national_code: nationalCode }).then(user => {
|
|
if (user && user.national_code === nationalCode && user._id.toString() !== req.body._id)
|
|
return Promise.reject(new Error('کاربر با این کد ملی از قبل وجود دارد'))
|
|
else return true
|
|
})
|
|
}),
|
|
|
|
body('province_id').notEmpty().withMessage(_faSr.required.province),
|
|
|
|
body('city_id').notEmpty().withMessage(_faSr.required.city),
|
|
|
|
body('address')
|
|
.notEmpty()
|
|
.withMessage(_faSr.required.address)
|
|
.bail()
|
|
.custom((value, { req }) => {
|
|
if (!isPersianWithDigits(value)) return Promise.reject(new Error('لطفا با حروف فارسی تایپ کنید'))
|
|
else return true
|
|
}),
|
|
|
|
body('postal_code')
|
|
.notEmpty()
|
|
.withMessage(_faSr.required.postal_code)
|
|
.bail()
|
|
.isNumeric()
|
|
.withMessage(_faSr.format.number),
|
|
|
|
body('tel_number')
|
|
.notEmpty()
|
|
.withMessage(_faSr.required.phone_number)
|
|
.bail()
|
|
.isNumeric()
|
|
.withMessage(_faSr.format.phone_number),
|
|
|
|
body('mobile_number')
|
|
.notEmpty()
|
|
.withMessage(_faSr.required.phone_number)
|
|
.bail()
|
|
.custom((value, { req }) => {
|
|
const mobileNStatus = checkMobileNumber(value)
|
|
if (!mobileNStatus) return Promise.reject(_faSr.format.phone_number)
|
|
else return Promise.resolve()
|
|
})
|
|
.bail()
|
|
.custom((value, { req }) => {
|
|
const mobileNumber = value.trim()
|
|
return User.findOne({ mobile_number: mobileNumber }).then(user => {
|
|
if (user && user.mobile_number === mobileNumber && user._id.toString() !== req.body._id)
|
|
return Promise.reject(new Error('کاربر با این شماره موبایل از قبل وجود دارد'))
|
|
else return true
|
|
})
|
|
}),
|
|
|
|
body('email')
|
|
.notEmpty()
|
|
.withMessage(_faSr.required.email)
|
|
.bail()
|
|
.isEmail()
|
|
.withMessage(_faSr.format.email)
|
|
.bail()
|
|
.custom((value, { req }) => {
|
|
const email = value.trim().toLowerCase()
|
|
return User.findOne({ email }).then(user => {
|
|
if (user && user.email === email && user._id.toString() !== req.body._id)
|
|
return Promise.reject(_faSr.duplicated.email)
|
|
else return true
|
|
})
|
|
})
|
|
],
|
|
checkValidations(validationResult),
|
|
async (req, res) => {
|
|
const {
|
|
first_name,
|
|
last_name,
|
|
national_code,
|
|
province_id,
|
|
province_name,
|
|
city_id,
|
|
city_name,
|
|
address,
|
|
postal_code,
|
|
tel_number,
|
|
mobile_number,
|
|
email,
|
|
store_name
|
|
} = req.body
|
|
|
|
const MongoData = {
|
|
last_name,
|
|
province_id,
|
|
province_name,
|
|
city_id,
|
|
city_name,
|
|
address,
|
|
postal_code,
|
|
tel_number,
|
|
store_name
|
|
}
|
|
MongoData.first_name = nameOptimizer(first_name)
|
|
MongoData.national_code = national_code.trim()
|
|
MongoData.mobile_number = normalizeMobileNumber(mobile_number)
|
|
MongoData.email = email.trim().toLowerCase()
|
|
|
|
try {
|
|
const user_id = req.params.id
|
|
const user = await User.findById(user_id)
|
|
if (!user) {
|
|
return res404(res, _faSr.not_found.user_id)
|
|
}
|
|
|
|
|
|
// check if need to ferify email or mobile
|
|
const newEmail = user.email !== MongoData.email
|
|
const newMobile = user.mobile_number !== MongoData.mobile_number
|
|
if (newEmail) user.email_confirmed = false
|
|
if (newMobile) user.mobile_confirmed = false
|
|
|
|
// save new info to arpa
|
|
await updateUserOnArpa(MongoData, user.verity_businessID, 'verity')
|
|
await updateUserOnArpa(MongoData, user.panatech_businessID, 'panatech')
|
|
|
|
// save new info to user
|
|
user.first_name = MongoData.first_name
|
|
user.last_name = MongoData.last_name
|
|
user.national_code = MongoData.national_code
|
|
user.province_id = MongoData.province_id
|
|
user.province_name = MongoData.province_name
|
|
user.city_id = MongoData.city_id
|
|
user.city_name = MongoData.city_name
|
|
user.address = MongoData.address
|
|
user.postal_code = MongoData.postal_code
|
|
user.tel_number = MongoData.tel_number
|
|
user.store_name = MongoData.store_name
|
|
user.mobile_number = MongoData.mobile_number
|
|
user.email = MongoData.email
|
|
|
|
|
|
|
|
await user.save()
|
|
|
|
// send confirmation key after user saved
|
|
if (newEmail) await sendConfirmationEmail(user_id)
|
|
if (newMobile) await sendConfirmationSMS(user_id)
|
|
|
|
return res.json({ message: _faSr.response.success_save })
|
|
} catch (e) {
|
|
console.log('Arpa Error during update user --', e)
|
|
return res500(res, _faSr.response.problem)
|
|
}
|
|
}
|
|
]
|
|
|
|
module.exports.updateUserByAdmin = [
|
|
[
|
|
body('first_name')
|
|
.notEmpty()
|
|
.withMessage(_faSr.required.first_name)
|
|
.bail()
|
|
.isLength({ min: 2 })
|
|
.withMessage(_faSr.min_char.min2)
|
|
.bail()
|
|
.custom((value, { req }) => {
|
|
if (removeWhiteSpaces(value).length < 2) return Promise.reject(_faSr.min_char.min2)
|
|
if (!isPersian(value)) return Promise.reject(new Error('لطفا با حروف فارسی تایپ کنید'))
|
|
else return true
|
|
}),
|
|
|
|
body('last_name')
|
|
.notEmpty()
|
|
.withMessage(_faSr.required.first_name)
|
|
.bail()
|
|
.isLength({ min: 2 })
|
|
.withMessage(_faSr.min_char.min2)
|
|
.bail()
|
|
.custom((value, { req }) => {
|
|
if (removeWhiteSpaces(value).length < 2) return Promise.reject(_faSr.min_char.min2)
|
|
if (!isPersian(value)) return Promise.reject(new Error('لطفا با حروف فارسی تایپ کنید'))
|
|
else return true
|
|
}),
|
|
|
|
body('national_code')
|
|
.notEmpty()
|
|
.withMessage(_faSr.required.national_code)
|
|
.bail()
|
|
.custom((value, { req }) => {
|
|
if (checkNationalCode(value)) return true
|
|
else return Promise.reject(_faSr.format.national_code)
|
|
})
|
|
.custom((value, { req }) => {
|
|
const nationalCode = value.trim()
|
|
return User.findOne({ national_code: nationalCode }).then(user => {
|
|
if (user && user.national_code === nationalCode && user._id.toString() !== req.body._id)
|
|
return Promise.reject(new Error('کاربر با این کد ملی از قبل وجود دارد'))
|
|
else return true
|
|
})
|
|
}),
|
|
|
|
body('province_id').notEmpty().withMessage(_faSr.required.province),
|
|
|
|
body('city_id').notEmpty().withMessage(_faSr.required.city),
|
|
|
|
body('address')
|
|
.notEmpty()
|
|
.withMessage(_faSr.required.address)
|
|
.bail()
|
|
.custom((value, { req }) => {
|
|
if (!isPersianWithDigits(value)) return Promise.reject(new Error('لطفا با حروف فارسی تایپ کنید'))
|
|
else return true
|
|
}),
|
|
|
|
body('postal_code')
|
|
.notEmpty()
|
|
.withMessage(_faSr.required.postal_code)
|
|
.bail()
|
|
.isNumeric()
|
|
.withMessage(_faSr.format.number),
|
|
|
|
body('tel_number')
|
|
.notEmpty()
|
|
.withMessage(_faSr.required.phone_number)
|
|
.bail()
|
|
.isNumeric()
|
|
.withMessage(_faSr.format.phone_number),
|
|
|
|
body('mobile_number')
|
|
.notEmpty()
|
|
.withMessage(_faSr.required.phone_number)
|
|
.bail()
|
|
.custom((value, { req }) => {
|
|
const mobileNStatus = checkMobileNumber(value)
|
|
if (!mobileNStatus) return Promise.reject(_faSr.format.phone_number)
|
|
else return Promise.resolve()
|
|
})
|
|
.bail()
|
|
.custom((value, { req }) => {
|
|
const mobileNumber = value.trim()
|
|
return User.findOne({ mobile_number: mobileNumber }).then(user => {
|
|
if (user && user.mobile_number === mobileNumber && user._id.toString() !== req.body._id)
|
|
return Promise.reject(new Error('کاربر با این شماره موبایل از قبل وجود دارد'))
|
|
else return true
|
|
})
|
|
}),
|
|
|
|
body('email')
|
|
.notEmpty()
|
|
.withMessage(_faSr.required.email)
|
|
.bail()
|
|
.isEmail()
|
|
.withMessage(_faSr.format.email)
|
|
.bail()
|
|
.custom((value, { req }) => {
|
|
const email = value.trim().toLowerCase()
|
|
return User.findOne({ email }).then(user => {
|
|
if (user && user.email === email && user._id.toString() !== req.body._id)
|
|
return Promise.reject(_faSr.duplicated.email)
|
|
else return true
|
|
})
|
|
})
|
|
],
|
|
checkValidations(validationResult),
|
|
async (req, res) => {
|
|
const {
|
|
first_name,
|
|
last_name,
|
|
national_code,
|
|
province_id,
|
|
province_name,
|
|
city_id,
|
|
city_name,
|
|
address,
|
|
postal_code,
|
|
tel_number,
|
|
mobile_number,
|
|
email,
|
|
store_name
|
|
} = req.body
|
|
|
|
const MongoData = {
|
|
last_name,
|
|
province_id,
|
|
province_name,
|
|
city_id,
|
|
city_name,
|
|
address,
|
|
postal_code,
|
|
tel_number,
|
|
store_name
|
|
}
|
|
MongoData.first_name = nameOptimizer(first_name)
|
|
MongoData.national_code = national_code.trim()
|
|
MongoData.mobile_number = normalizeMobileNumber(mobile_number)
|
|
MongoData.email = email.trim().toLowerCase()
|
|
|
|
try {
|
|
const user_id = req.params.id
|
|
const user = await User.findById(user_id)
|
|
if (!user) return res404(res, _faSr.not_found.user_id)
|
|
|
|
// check if need to ferify email or mobile
|
|
const newEmail = user.email !== MongoData.email
|
|
const newMobile = user.mobile_number !== MongoData.mobile_number
|
|
if (newEmail) user.email_confirmed = false
|
|
if (newMobile) user.mobile_confirmed = false
|
|
|
|
// save new info to arpa
|
|
await updateUserOnArpa(MongoData, user.verity_businessID, 'verity')
|
|
await updateUserOnArpa(MongoData, user.panatech_businessID, 'panatech')
|
|
|
|
// save new info to user
|
|
user.first_name = MongoData.first_name
|
|
user.last_name = MongoData.last_name
|
|
user.national_code = MongoData.national_code
|
|
user.province_id = MongoData.province_id
|
|
user.province_name = MongoData.province_name
|
|
user.city_id = MongoData.city_id
|
|
user.city_name = MongoData.city_name
|
|
user.address = MongoData.address
|
|
user.postal_code = MongoData.postal_code
|
|
user.tel_number = MongoData.tel_number
|
|
user.store_name = MongoData.store_name
|
|
user.mobile_number = MongoData.mobile_number
|
|
user.email = MongoData.email
|
|
|
|
await user.save()
|
|
|
|
// send confirmation key after user saved
|
|
if (newEmail) await sendConfirmationEmail(user_id)
|
|
if (newMobile) await sendConfirmationSMS(user_id)
|
|
|
|
return res.json({ message: _faSr.response.success_save })
|
|
} catch (e) {
|
|
console.log('Arpa Error during update user --', e)
|
|
return res500(res, _faSr.response.problem)
|
|
}
|
|
}
|
|
]
|
|
|
|
/// //////////////////////////////////////////////////////////////////// authentication
|
|
|
|
/// //////// Login
|
|
|
|
module.exports.webLogin = [
|
|
[
|
|
body('username')
|
|
.isLength({ min: 4 })
|
|
.withMessage(_faSr.min_char.min4)
|
|
.bail()
|
|
.if((value, { req }) => {
|
|
return req.body.password && req.body.password.length >= 4
|
|
})
|
|
.custom((value, { req }) => {
|
|
return User.findOne({
|
|
$or: [{ email: value.toLowerCase().trim() }, { national_code: value }, { username: value }]
|
|
}).then(user => {
|
|
if (!user) return Promise.reject(_faSr.not_found.password)
|
|
else return true
|
|
})
|
|
}),
|
|
|
|
body('password')
|
|
.notEmpty()
|
|
.withMessage(_faSr.required.password)
|
|
.bail()
|
|
.isLength({ min: 4 })
|
|
.withMessage(_faSr.min_char.min4),
|
|
|
|
body('remember_me')
|
|
.exists()
|
|
.withMessage(_faSr.required.remember_me)
|
|
.bail()
|
|
.isBoolean()
|
|
.withMessage(_faSr.format.boolean)
|
|
],
|
|
checkValidations(validationResult),
|
|
async (req, res) => {
|
|
try {
|
|
const { username, password } = req.body
|
|
const user = await User.findOne({
|
|
$or: [{ email: username.toLowerCase().trim() }, { national_code: username }, { username }]
|
|
})
|
|
if (!user) throw new Error('err')
|
|
const passwordMatch = await bcrypt.compare(password, user.password)
|
|
if (!passwordMatch) throw new Error('err')
|
|
const token = await jwt.sign({ _id: user._id }, secretKey, {
|
|
expiresIn: req.body.remember_me ? '30d' : '7d'
|
|
})
|
|
user.token = token
|
|
await user.save()
|
|
return res.json({ token })
|
|
} catch (err) {
|
|
return res.status(422).json({
|
|
validation: { username: { msg: _faSr.not_found.password } }
|
|
})
|
|
}
|
|
}
|
|
]
|
|
|
|
module.exports.appLogin = [
|
|
[
|
|
body('username')
|
|
.isLength({ min: 4 })
|
|
.withMessage(_faSr.min_char.min4)
|
|
.bail()
|
|
.if((value, { req }) => {
|
|
return req.body.password && req.body.password.length >= 4
|
|
})
|
|
.custom((value, { req }) => {
|
|
return User.findOne({
|
|
$or: [{ email: value.toLowerCase().trim() }, { national_code: value }]
|
|
}).then(user => {
|
|
if (!user) return Promise.reject(_faSr.not_found.password)
|
|
else return true
|
|
})
|
|
}),
|
|
|
|
body('password')
|
|
.notEmpty()
|
|
.withMessage(_faSr.required.password)
|
|
.bail()
|
|
.isLength({ min: 4 })
|
|
.withMessage(_faSr.min_char.min4)
|
|
],
|
|
checkValidations(validationResult),
|
|
async (req, res) => {
|
|
try {
|
|
const { username, password } = req.body
|
|
const user = await User.findOne({
|
|
$or: [{ email: username.toLowerCase().trim() }, { national_code: username }]
|
|
})
|
|
if (!user) throw new Error('err')
|
|
|
|
const passwordMatch = await bcrypt.compare(password, user.password)
|
|
if (!passwordMatch) throw new Error('err')
|
|
|
|
const token = await jwt.sign({ _id: user._id }, secretKey, {
|
|
expiresIn: '60d'
|
|
})
|
|
user.appToken = token
|
|
await user.save()
|
|
return res.json({ token })
|
|
} catch (err) {
|
|
return res.status(422).json({
|
|
validation: { username: { msg: _faSr.not_found.password } }
|
|
})
|
|
}
|
|
}
|
|
]
|
|
|
|
/// //////// logout
|
|
module.exports.webLogout = [
|
|
async (req, res) => {
|
|
try {
|
|
const token = req.headers?.authorization
|
|
if (!token) throw new Error('err')
|
|
|
|
const user = await User.findOne({ token })
|
|
if (!user) throw new Error('err')
|
|
|
|
user.token = null
|
|
await user.save()
|
|
|
|
return res.json({ message: _faSr.response.logged_out })
|
|
} catch (err) {
|
|
return res.status(401).json({ message: _faSr.response.not_logged_in })
|
|
}
|
|
}
|
|
]
|
|
|
|
module.exports.appLogout = [
|
|
async (req, res) => {
|
|
try {
|
|
const token = req.headers?.authorization
|
|
if (!token) throw new Error('err')
|
|
|
|
const user = await User.findOne({ appToken: token })
|
|
if (!user) throw new Error('err')
|
|
|
|
user.appToken = null
|
|
await user.save()
|
|
|
|
return res.json({ message: _faSr.response.logged_out })
|
|
} catch (err) {
|
|
return res.status(401).json({ message: _faSr.response.not_logged_in })
|
|
}
|
|
}
|
|
]
|
|
|
|
/// //////// get user
|
|
module.exports.getUser = [
|
|
async (req, res) => {
|
|
try {
|
|
const token = req.headers?.authorization
|
|
if (!token) throw new Error('err')
|
|
|
|
const decoded = jwt.verify(token, secretKey)
|
|
if (!decoded) throw new Error('err')
|
|
|
|
const user = await User.findById(decoded?._id).select(
|
|
'-token -appToken -emailConfirmationKey -mobileConfirmationKey -password -resetPassToken'
|
|
)
|
|
return res.status(200).json({ user })
|
|
} catch (err) {
|
|
console.log('🚀 ~ file: userController.js ~ line 1580 ~ err', err)
|
|
return res.status(401).json({ message: 'unauthenticated' })
|
|
}
|
|
}
|
|
]
|
|
|
|
|
|
|