Files
hamid.zarghami1@gmail.com e644edbd65 transfer project in github
2024-05-12 15:29:27 +03:30

1520 lines
51 KiB
JavaScript

import moment from "moment-jalaali";
import * as path from "path";
const xlsx = require('xlsx');
const User = require('../models/User')
const Job = require('../models/Job')
const StoreInfo = require('../models/StoreInfo')
const Food = require('../models/Food')
const DiscountCode = require('../models/DiscountCode')
const GetTokenLimit = require('../models/GetTokenLimit')
const {body, validationResult} = require('express-validator')
const bcrypt = require('bcryptjs')
const jwt = require('jsonwebtoken')
const sharp = require('sharp')
const {secretKey, getID} = require('./../authentication')
const {sms} = require('../SMSModule')
const {_sr} = require('../plugins/serverResponses')
const {res404, res500, hasWhiteSpaces, isLatinCharactersWithSymbol, generateRandomDigits, removeWhiteSpaces, checkValidations} = require('../plugins/controllersHelperFunctions')
const permissions = require('../plugins/permissions')
const fs = require('fs')
// const path = require('path')
const axios = require('axios')
const {sendSingle, sendMulti} = require('./../plugins/pushNotif').notification
////// variables
const profileWidth = 500
const profileHeight = 500
const profileQuality = 100
const apiKey = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6ImRiYjIwMmRhYzAxYzFjNzgwYjgxNWQyZDgyMWNmNmY1Njk0MThhMGE3N2Q1M2Y0OTZkYzQzYTgxMmNmN2U3ZWJjNzI5MjY5YjkxMjA4MTYyIn0.eyJhdWQiOiIxNDk3OSIsImp0aSI6ImRiYjIwMmRhYzAxYzFjNzgwYjgxNWQyZDgyMWNmNmY1Njk0MThhMGE3N2Q1M2Y0OTZkYzQzYTgxMmNmN2U3ZWJjNzI5MjY5YjkxMjA4MTYyIiwiaWF0IjoxNjI3MzI2Mzc0LCJuYmYiOjE2MjczMjYzNzQsImV4cCI6MTYyOTkxODM3NCwic3ViIjoiIiwic2NvcGVzIjpbImJhc2ljIl19.hyKNSy4fmPps6yIdm33Wof-mES9ujh5lmI3VFWyecbkNCm9ATPwsZ9s53A3a1wPJmHfLBXpCcob5NGL-GjZlVfqfRBiReRMr_iniCjUOnqENfFwVEJutxI-xrzVe7PZzOgx1Vr6WwSUHvQ36eJSS1lBlHlqCgwRbkG0hs4YdZsKhzhfYdlAluNw9djjUAMbRWZVL0EluP9CYko4w8tB0KHUZMZYGQcevCfb_3OU9ygHo7B--Z5aTPfm7IK4eP0gHsZ_t857B3tu3ZJB1mkgxc2R9gZUflKqj1ZqkYiR0uMGP-571enXh6pYQLXL2k-gOxLIedCaE6XytxVXhENnotA';
// user scores
// const userRegistrationScore = 100
// const userEmailVerifyScore = 50
// const invitePoint = 5
const limit = 20
/////////////////////////////////////////////////////////////////////// admin
module.exports.register_admin = [
[
body('first_name')
.notEmpty().withMessage(_sr['fa'].required.first_name),
body('last_name')
.notEmpty().withMessage(_sr['fa'].required.last_name),
body('username')
.isLength({min: 2}).withMessage(_sr['fa'].min_char.min2)
.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)
})
],
async (req, res) => {
const errors = validationResult(req)
if (!errors.isEmpty()) return res.status(422).json({validation: errors.mapped()})
const creatorID = await getID(req)
const {username, first_name, last_name, email, mobile_number , permissions , branches} = req.body
const data = {username, first_name, last_name, email, mobile_number}
data.permissions = JSON.parse(permissions)
data.branches = JSON.parse(branches)
if (req.files && req.files.profile_pic) {
const image = req.files.profile_pic
const imageName = 'user_' + Date.now() + '_' + req.body.username + '.' + image.mimetype.split('/')[1]
data.profile_pic = 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)
}
}
bcrypt.genSalt(10, (err, salt) => {
bcrypt.hash(req.body.password, salt, (err, hash) => {
if (err) console.log(err)
data.password = hash
data.scope = ['admin']
data._creator = creatorID
const newAdmin = new User(data)
newAdmin.save(err => {
if (err) return res500(res, err)
return res.json({message: _sr['fa'].response.success_save})
})
})
})
}
]
module.exports.get_all_admins = [
(req, res) => {
const branchId = req?.params?.branchId
// const filter = req?.user?.permissions.includes('super-admin') ? {scope: ['admin'], private: false} : {scope: ['admin'], private: false , branches : branchId}
const filter = {scope: ['admin'], private: false, branches: branchId}
User.paginate(filter, {
page: req?.query?.page,
limit,
select: '-password -token'
}, (err, users) => {
if (err) return res500(res, err.message)
else return res.json(users)
})
}
]
module.exports.get_all_users = [
(req, res) => {
const branchId = req?.params?.branchId
const filter = {registration_done: true, scope: ['user'], branches : branchId}
User.paginate(filter, {
page: req.query.page,
limit,
select: '-password -token'
}, (err, users) => {
if (err) return res500(res, err)
else return res.json(users)
})
}
]
module.exports.get_all_users_for_reports = [
async (req, res) => {
try {
const branchId = req?.params?.branchId
const filter = {registration_done: true, scope: ['user'] , branches : branchId}
const users = await User.find(filter).select('-password -token')
return res.json(users)
} catch (error) {
return res500(res, _sr['fa'].response.unknownError)
}
}
]
module.exports.get_all_users_without_paginate = [
(req, res) => {
const branchId = req?.params?.branchId
const filter = {registration_done: true, scope: ['user'] , branches : branchId}
User.find(filter).select('-password -token').exec((err, users) => {
if (err) return res500(res, err)
else return res.json(users)
})
}
]
module.exports.get_one_admin = [
(req, res) => {
User.findById(req.params.id).select('-password -token ').exec(async (err, user) => {
if (err || !user) return res404(res, err)
const clone = JSON.parse(JSON.stringify(user))
try {
clone.discount_codes = await DiscountCode.find({discount_user_id: user._id})
return res.json(clone)
} catch (e) {
return res500(res, e)
}
})
}
]
module.exports.permissions = [
(req, res) => {
return res.json(permissions)
}
]
module.exports.update_admin = [
[
body('first_name')
.notEmpty().withMessage(_sr['fa'].required.first_name),
body('last_name')
.notEmpty().withMessage(_sr['fa'].required.last_name),
body('username')
.isLength({min: 2}).withMessage(_sr['fa'].min_char.min2)
.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 && user._id.toString() !== req.params.id) 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)
})
],
async (req, res) => {
const errors = validationResult(req)
if (!errors.isEmpty()) return res.status(422).json({validation: errors.mapped()})
const creatorID = await getID(req)
const {username, first_name, last_name, email, mobile_number, permissions, branches} = req.body
const data = {username, first_name, last_name, email, mobile_number}
data._creator = creatorID
data.permissions = JSON.parse(permissions)
data.branches = JSON.parse(branches)
if (req.files && req.files.profile_pic) {
const image = req.files.profile_pic
const imageName = 'user_' + Date.now() + '_' + req.body.username + '.' + image.mimetype.split('/')[1]
data.profile_pic = 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)
}
}
User.findByIdAndUpdate(req.params.id, data, (err, oldData) => {
if (err || !oldData) return res404(res, err)
if (req.files && req.files.profile_pic && oldData.profile_pic) {
fs.unlink(`./static/${oldData.profile_pic}`, err => {
if (err) console.log(err)
})
}
return res.json({message: _sr['fa'].response.success_save})
})
}
]
module.exports.remove_admin = [
(req, res) => {
User.findByIdAndDelete(req.params.id, (err, data) => {
if (err || !data) return res404(res, err)
if (data.profile_pic) {
fs.unlink(`./static/${data.profile_pic}`, err => {
if (err) console.log(err)
})
}
return res.json({message: _sr['fa'].response.success_remove})
})
}
]
module.exports.change_admin_password_by_another = [
[
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)
})
],
(req, res) => {
const errors = validationResult(req)
if (!errors.isEmpty()) return res.status(422).json({validation: errors.mapped()})
User.findById(req.params.id, (err, user) => {
if (err || !user) return res404(res, err)
bcrypt.genSalt(10, (err, salt) => {
bcrypt.hash(req.body.password, salt, (err, hash) => {
if (err) console.log(err)
user.password = hash
user.save(err => {
if (err) return res500(res, err)
return res.json({message: _sr['fa'].response.success_save})
})
})
})
})
}
]
////////////////////////////////////////////////////////////////////// user discount code
module.exports.generate_discount_code_for_users = [
[
body('discount_amount')
.notEmpty().withMessage(_sr['fa'].required.discount_amount)
.bail()
.isNumeric().withMessage(_sr['fa'].format.number),
body('discount_expire_date')
.notEmpty().withMessage(_sr['fa'].required.discount_expire_date),
body('discount_user_id')
.if((value, {req}) => !req.body.newDiscountIsPublic)
.notEmpty().withMessage(_sr['fa'].required.user_id),
body('newDiscountIsPublic')
.notEmpty().withMessage('Discount public status must be specified'),
body('publicDiscountIsAuto')
.notEmpty().withMessage('Discount public code method must be specified'),
body('customDiscountCode')
.if((value, {req}) => req.body.newDiscountIsPublic && !req.body.publicDiscountIsAuto)
.notEmpty().withMessage(_sr['fa'].required.discount_code),
body('branchId')
.notEmpty().withMessage(_sr['fa'].required.field)
.bail()
.custom((value, {req}) => {
return StoreInfo.findOne({_id: value})
.then(store => {
if (!store) return Promise.reject(_sr['fa'].not_found.item_id)
else return true
})
})
],
checkValidations(validationResult),
async (req, res) => {
const {branchId , discount_amount, discount_expire_date, discount_user_id, newDiscountIsPublic, publicDiscountIsAuto, customDiscountCode, menuTypeId} = req.body
async function generateDiscountCode() {
try {
let code = generateRandomDigits(6)
const checkDiscountCodes = await DiscountCode.findOne({discount_code: code, discount_user_id: discount_user_id, isPublic: false})
if (checkDiscountCodes) generateDiscountCode()
else return code
} catch (e) {
return res500(res, e)
}
}
async function generatePublicDiscountCode() {
try {
let code = generateRandomDigits(6)
const checkDiscountCodes = await DiscountCode.findOne({discount_code: code, isPublic: true})
if (checkDiscountCodes) generatePublicDiscountCode()
else return code
} catch (e) {
return res500(res, e)
}
}
const data = {
branchId,
discount_amount,
menuTypeId,
discount_expire_date: discount_expire_date
}
if (newDiscountIsPublic) {
data.isPublic = true
if (publicDiscountIsAuto) data.discount_code = await generatePublicDiscountCode()
else {
try {
const checkDiscountCodes = await DiscountCode.findOne({discount_code: customDiscountCode, isPublic: true})
if (checkDiscountCodes) return res.status(422).json({validation: {discount_code: {msg: 'کد تخفیف تکراری است'}}})
else data.discount_code = customDiscountCode
} catch (e) {
return res500(res, e)
}
}
const users = await User.find({registration_done : true , test : true}) //, test : true
const tokens = []
let mobiles = []
for (const user of users) {
if (user.fcmToken) tokens.push(user.fcmToken)
if (user.mobile_number) mobiles.push(user.mobile_number)
}
const smsTemplate = `با سلام یک عدد کد تخفیف ${data.discount_amount} درصدی تا تاریخ ${moment(data.discount_expire_date, 'X').format('jYYYY/jMM/jDD')} به شما اختصاص داده شد کد: ${data.discount_code} رستوران برگ لغو11`
//--------------------- send notif to user --------------------------
const messageUser = {
title: 'کد تخفیف',
body: smsTemplate
}
const payloadUser = {
notification: messageUser,
};
const inputUser = {
registrationTokens: tokens,
payload: payloadUser
}
await sendMulti(inputUser)
//-------------------------------------------------------------------
const smsResult = await sms(mobiles, smsTemplate)
if (!smsResult || !smsResult.data.IsSuccessful) {
console.log(smsResult)
// return res500(res, `مشکلی در ارسال پیامک پیش آمده است`)
}
} else {
data.discount_code = await generateDiscountCode()
data.discount_user_id = discount_user_id
const user = await User.findById(discount_user_id)
if (user) {
let smsTemplate = ''
if (user?.fromWhere === 'app') smsTemplate = `با سلام یک عدد کد تخفیف ${data.discount_amount} درصدی تا تاریخ ${moment(data.discount_expire_date, 'X').format('jYYYY/jMM/jDD')} به شما اختصاص داده شد کد: ${data.discount_code}
رستوران برگ
لینک : https://app.bargrestaurant.com/discountCode`
else smsTemplate = `با سلام یک عدد کد تخفیف ${data.discount_amount} درصدی تا تاریخ ${moment(data.discount_expire_date, 'X').format('jYYYY/jMM/jDD')} به شما اختصاص داده شد کد: ${data.discount_code} رستوران برگ
لینک : https://app.bargrestaurant.com/discountCodes
`
//--------------------- send notif to user --------------------------
const messageUser = {
title: 'کد تخفیف',
body: smsTemplate
}
const payloadUser = {
notification: messageUser,
};
const inputUser = {
registrationTokens: user.fcmToken,
payload: payloadUser
}
await sendSingle(inputUser)
//-------------------------------------------------------------------
const smsResult = await sms(user.mobile_number, smsTemplate)
if (!smsResult || !smsResult.data.IsSuccessful) {
console.log(smsResult)
// return res500(res, `مشکلی در ارسال پیامک پیش آمده است`)
}
}
}
const newDiscount = DiscountCode(data)
newDiscount.save((err, data) => {
if (err) return res500(res, err)
else return res.json(data)
})
}
]
module.exports.get_all_discounts_for_admin = [
(req, res) => {
const filter = {branchId: req?.params?.branchId}
DiscountCode.paginate(filter, {
page: req.query.page,
limit,
populate: {
path: 'discount_user_id',
select: 'first_name last_name business_code mobile_number score'
}
}, (err, data) => {
if (err) return res500(res, err)
else return res.json(data)
})
}
]
module.exports.delete_discount_code = [
(req, res) => {
DiscountCode.findByIdAndRemove(req.params.id, (err, oldData) => {
if (err || !oldData) return res404(res, err)
else return res.json({message: _sr['fa'].response.success_save})
})
}
]
module.exports.getAllDiscountCodeOfUser = [
async (req, res) => {
try {
const discounts = await DiscountCode.find({
branchId: req?.params?.branchId,
$or : [
{isPublic : true},
{
discount_user_id: req.user._id,
used_by: {'$nin': req.user._id},
discount_expire_date: {'$gte': +new Date().setHours(0, 0, 0, 0)}
}
]
})
const user = await User.findById(req.user._id).select('first_name last_name')
if (!user) return res404(res, 'اطلاعات کاربر یافت نشد')
const clone = JSON.parse(JSON.stringify(discounts))
clone.map(item => {
item.user = user
item.used = item.used_by.includes(req.user._id)
})
return res.json(clone)
} catch (error) {
return res500(res, _sr['fa'].response.unknownError)
}
}
]
/////////////////////////////////////////////////////////////////////// user
/////////////// user registration
module.exports.get_phone_number = [
[
body('mobile_number')
.notEmpty().withMessage(_sr['fa'].required.phone_number)
.bail()
.isMobilePhone().withMessage(_sr['fa'].format.phone_number)
],
checkValidations(validationResult),
async (req, res) => {
try {
let getTokenLimit = await GetTokenLimit.find({phone: req.body.mobile_number})
if (getTokenLimit.length) return res.status(429).json({message: 'شما هر دو دقیقه یکبار مجاز به گرفتن کد تایید می باشید'})
const user = await User.findOne({mobile_number: req.body.mobile_number})
if (user) {
if (user.registration_done) {
return res.json({
// hasAccount: true,
registration_done: user.registration_done
})
} else {
user.token = await generateRandomDigits(6)
user.save(err => {
if (err) return res500(res, err)
})
const smsTemplate = `
با تشکر از ثبت نام شما در برگ من
کد فعال سازی شما: ${user.token}
لغو11
`
const smsResult = await sms(req.body.mobile_number, smsTemplate)
if (!smsResult || !smsResult.data.IsSuccessful) {
console.log(smsResult)
return res500(res, `مشکلی در ارسال پیامک پیش آمده است`)
}
await GetTokenLimit.create({
phone: req.body.mobile_number
});
return res.json({
// hasAccount: true,
registration_done: user.registration_done
})
}
} else {
const data = {
mobile_number: req.body.mobile_number,
registration_done: false
}
let token = await generateRandomDigits(6)
data.token = token
const smsTemplate = `
با تشکر از ثبت نام شما در برگ من
کد فعال سازی شما: ${token}
لغو11
`
const smsResult = await sms(req.body.mobile_number, smsTemplate)
if (!smsResult || !smsResult.data.IsSuccessful) {
console.log(smsResult)
return res500(res, `مشکلی در ارسال پیامک پیش آمده است`)
}
await GetTokenLimit.create({
phone: req.body.mobile_number
});
const newUser = new User(data)
newUser.save((err, data) => {
if (err) return res500(res, err)
return res.json({registration_done: false})
})
}
} catch (e) {
console.log(e.message)
return res500(res, _sr['fa'].response.unknownError)
}
}
]
module.exports.resend_user_resgistration_token = [
async (req, res) => {
try {
const getTokenLimit = await GetTokenLimit.find({phone: req.params.mobile_number});
if (getTokenLimit.length) return res.status(429).json({message: 'شما هر دو دقیقه یکبار مجاز به گرفتن کد تایید می باشید'})
const user = await User.findOne({mobile_number: req.params.mobile_number})
if (user) {
const smsTemplate = `
با تشکر از ثبت نام شما در برگ من
کد فعال سازی شما: ${user.token}
لغو11
`
const smsResult = await sms(req.params.mobile_number, smsTemplate)
if (!smsResult || !smsResult.data.IsSuccessful) {
return res500(res, `مشکلی در ارسال پیامک پیش آمده است`)
}
await GetTokenLimit.create({
phone: req.params.mobile_number
});
return res.json({message: 'کد فعال سازی دوباره برای شما ارسال شد.'})
} else return res404(res, 'برای این شماره هیچ کد تایید ای یافت نشد.')
} catch (e) {
console.log('resend_user_resgistration_token', error.message)
return res404(res, 'برای این شماره هیچ کد تایید ای یافت نشد.')
}
}
]
module.exports.generate_temp_token_for_user = [
async (req, res) => {
try {
const getTokenLimit = await GetTokenLimit.find({phone: req.params.mobile_number});
if (getTokenLimit.length) return res.status(429).json({message: 'شما هر دو دقیقه یکبار مجاز به گرفتن کد تایید می باشید'})
const user = await User.findOne({mobile_number: req.params.mobile_number})
if (user) {
const token = await generateRandomDigits(6)
const smsTemplate = `
با تشکر از ثبت نام شما در برگ من
کد فعال سازی شما: ${token}
لغو11
`
user.token = token
await user.save()
const smsResult = await sms(req.params.mobile_number, smsTemplate)
if (!smsResult || !smsResult.data.IsSuccessful) {
return res500(res, `مشکلی در ارسال پیامک پیش آمده است`)
}
await GetTokenLimit.create({
phone: req.params.mobile_number
});
return res.json({message: 'کد فعال سازی برای شما ارسال شد.'})
} else return res404(res, 'کاربر مورد نظر وجود ندارد')
} catch (error) {
console.log('generate_temp_token_for_user', error.message)
return res500(res, _sr['fa'].response.unknownError);
}
}
]
module.exports.validate_user_temp_token = [
[
body('mobile_number')
.notEmpty().withMessage(_sr['fa'].required.phone_number),
body('token')
.notEmpty().withMessage(_sr['fa'].required.token)
],
checkValidations(validationResult),
async (req, res) => {
try {
const user = await User.findOne({mobile_number: req.body.mobile_number, token: req.body.token})
if (user) {
user.token = null
const response = {registration_done: user.registration_done}
if (user.registration_done) {
response.token = await jwt.sign({_id: user._id}, secretKey, {expiresIn: '1000d'})
user.token = response.token;
user.fromWhere = req.body?.fromWhere;
user.save((err, newUserData) => {
if (err) return res500(res, _sr['fa'].response.unknownError)
return res.json(response)
})
} else {
return res.json(response)
}
} else return res404(res, 'کد تایید معتبر نمیباشد.')
} catch (e) {
return res404(res, 'برای این شماره هیچ کد تایید ای یافت نشد.')
}
}
]
module.exports.add_name_to_user_registration = [
[
body('first_name')
.notEmpty().withMessage(_sr['fa'].required.first_name)
.bail()
.custom((value, {req}) => {
if (removeWhiteSpaces(value).length < 3) return Promise.reject(_sr['fa'].min_char.min2)
else return true
}),
body('last_name')
.notEmpty().withMessage(_sr['fa'].required.last_name)
.bail()
.custom((value, {req}) => {
if (removeWhiteSpaces(value).length < 3) return Promise.reject(_sr['fa'].min_char.min2)
else return true
}),
body('job')
.notEmpty().withMessage(_sr['fa'].required.field),
body('invitation')
.custom((value, {req}) => {
if (value) {
return User.findOne({business_code: value, registration_done: true})
.then(user => {
if (!user) return Promise.reject('کد دعوت وارد شده صحیح نمی باشد')
else return true
})
} else {
return true
}
}),
],
checkValidations(validationResult),
(req, res) => {
User.findOne({mobile_number: req.body.mobile_number}, (err, user) => {
if (err || !user) return res404(res, _sr['fa'].not_found.user_id)
user.first_name = req.body.first_name
user.last_name = req.body.last_name
user.job = req.body.job
user.invitation = req.body.invitation
user.save((err, newUserData) => {
if (err) return res500(res, err)
return res.json({message: _sr['fa'].response.success_save})
})
})
}
]
module.exports.add_password_to_user_registration = [
[
body('password')
.custom((value, {req}) => {
if (removeWhiteSpaces(value).length < 4) return Promise.reject(_sr['fa'].min_char.min4)
else return true
}),
body('password_confirmation')
.custom((value, {req}) => {
if (removeWhiteSpaces(value).length < 4) return Promise.reject(_sr['fa'].min_char.min4)
else return true
})
.custom((value, {req}) => {
if (value === req.body.password) return true
else return Promise.reject(_sr['fa'].response.passwords_not_match)
}),
body('branchId')
.notEmpty().withMessage(_sr['fa'].required.field)
.bail()
.custom((value, {req}) => {
return StoreInfo.findOne({_id: value})
.then(store => {
if (!store) return Promise.reject(_sr['fa'].not_found.item_id)
else return true
})
})
],
checkValidations(validationResult),
async (req, res) => {
try {
const {branchId, mobile_number, password, deviceId, platform ,fromWhere} = req.body
const user = await User.findOne({mobile_number: mobile_number})
if (!user) return res404(res, _sr['fa'].not_found.user_id)
const storeInfo = await StoreInfo.findOne({_id : branchId})
const userInvite = await User.findOne({business_code: user.invitation, registration_done: true})
// generate user password hash
const salt = await bcrypt.genSalt(10)
const hash = await bcrypt.hash(password, salt)
// generate user business code
const users = await User.find({registration_done: true, scope: ['user']})
const businessCode = new Date().getFullYear().toString() + (users.length + 1).toString()
// add new fields to user
const token = jwt.sign({_id: user._id}, secretKey, {expiresIn: '1000d'})
user.token = token
user.password = hash
user.business_code = businessCode
user.registration_done = true
user.score = storeInfo?.userRegistrationScore
user.scoreLogs = [
{
score: storeInfo?.userRegistrationScore,
forWhat: 'register',
action: 'increase'
}
]
user.deviceId = deviceId
user.platform = platform
user.fromWhere = fromWhere
user.branches = [branchId]
if (userInvite) {
userInvite.score = userInvite.score + storeInfo?.invitePoint
userInvite.scoreLogs = [
{
score: storeInfo?.invitePoint,
forWhat: 'invite',
action: 'increase'
}
]
await userInvite.save()
}
// save user
user.save((err, newUserData) => {
if (err) return res500(res, err)
return res.json({token: token})
})
} catch (e) {
return res500(res, e.message)
}
}
]
module.exports.change_user_password = [
[
body('password')
.custom((value, {req}) => {
if (removeWhiteSpaces(value).length < 4) return Promise.reject(_sr['fa'].min_char.min4)
else return true
}),
body('password_confirmation')
.custom((value, {req}) => {
if (removeWhiteSpaces(value).length < 4) return Promise.reject(_sr['fa'].min_char.min4)
else return true
})
.custom((value, {req}) => {
if (value === req.body.password) return true
else return Promise.reject(_sr['fa'].response.passwords_not_match)
})
],
checkValidations(validationResult),
async (req, res) => {
try {
const userID = await getID(req)
const user = await User.findById(userID)
if (!user) return res404(res, _sr['fa'].not_found.user_id)
// generate user password hash
const salt = await bcrypt.genSalt(10)
user.password = await bcrypt.hash(req.body.password, salt)
user.token = null
user.save((err, newUserData) => {
if (err) return res500(res, err)
return res.json({message: _sr['fa'].response.success_save})
})
} catch (e) {
return res500(res, e)
}
}
]
module.exports.update_user = [
[
body('first_name')
.notEmpty().withMessage(_sr['fa'].required.first_name)
.bail()
.custom((value, {req}) => {
if (removeWhiteSpaces(value).length < 3) return Promise.reject(_sr['fa'].min_char.min2)
else return true
}),
body('last_name')
.notEmpty().withMessage(_sr['fa'].required.last_name)
.bail()
.custom((value, {req}) => {
if (removeWhiteSpaces(value).length < 3) return Promise.reject(_sr['fa'].min_char.min2)
else return true
}),
body('birth_date')
.optional()
.isString().withMessage(_sr['fa'].required.birthdate),
body('marriage_date')
.optional()
.isString().withMessage(_sr['fa'].required.field),
body('job')
.optional()
.isString().withMessage(_sr['fa'].required.field),
body('national_code')
.optional()
.isString().withMessage(_sr['fa'].required.national_code)
.bail()
.custom((value, {req}) => {
if (value && removeWhiteSpaces(value).length !== 10) return Promise.reject(_sr['fa'].min_char.min10)
else return true
}),
],
checkValidations(validationResult),
async (req, res) => {
try {
const {first_name, last_name, email, birth_date, marriage_date, job, national_code, showBirthDate} = req.body
const userID = await getID(req)
User.findById(userID, (err, user) => {
if (err || !user) return res404(res, err)
user.first_name = first_name
user.last_name = last_name
user.email = email
user.birth_date = birth_date
// user.showBirthDate = showBirthDate
user.marriage_date = marriage_date
user.job = job
user.national_code = national_code
// if (email?.length){
// user.score += userEmailVerifyScore
// user.scoreLogs = [
// {
// score : userEmailVerifyScore,
// forWhat : 'emailVerify',
// action : 'increase'
// }
// ]
// }
user.save(err => {
if (err) return res500(res, err)
return res.json({message: _sr['fa'].response.success_save})
})
})
} catch (e) {
return res500(res, e)
}
}
]
module.exports.exportExel = [
async (req, res) => {
try {
const admin = await User.findOne({_id : req?.params?.id , scope : 'admin'})
if (!admin) return res.status(403).json({message : 'شما اجازه گرفتن خروجی اکسل را ندارید'})
const users = await User.find({scope: 'user', registration_done: true}).select('first_name last_name business_code birth_date marriage_date national_code bagAmount score mobile_number')
const data = users.map(user => {
return [
user.mobile_number,
user.first_name,
user.last_name,
user.business_code,
moment(user.birth_date).format('jYYYY/jMM/jDD') === 'Invalid date' ? '' : moment(user.birth_date).format('jYYYY/jMM/jDD'),
moment(user.marriage_date).format('jYYYY/jMM/jDD') === 'Invalid date' ? '' : moment(user.marriage_date).format('jYYYY/jMM/jDD'),
user.national_code,
user.bagAmount.toLocaleString() + ' ریال',
user.score
];
});
const workSheetColumn = [
'شماره موبایل','نام','نام خانوادگی', 'کد مشتری', 'تاریخ تولد', 'سالگرد ازدواج', 'کد ملی', 'کیف پول', 'امتیاز'
];
const workbook = xlsx.utils.book_new()
const workSheetData = [
workSheetColumn,
...data
];
const workSheet = xlsx.utils.aoa_to_sheet(workSheetData)
xlsx.utils.book_append_sheet(workbook, workSheet, "لیست کاربران")
xlsx.writeFile(workbook, path.resolve('./static/export/usersList.xlsx'))
return res.download(`./static/export/usersList.xlsx`)
} catch (e) {
return res500(res, _sr['fa'].response.unknownError)
}
}
]
/////////////// user addresses
module.exports.add_address_to_user = [
[
body('title')
.optional().isString().withMessage(`فرمت عنوان از نوع رشته می باشد`),
body('province')
.notEmpty().withMessage(_sr['fa'].required.province),
body('city')
.notEmpty().withMessage(_sr['fa'].required.city),
// .bail()
// .custom((value, {req}) => {
// if (req.body.city.localeCompare('اراک') !== 0) return Promise.reject('آدرس خارج از محدوده مد نظر می باشد')
// else return true
// }),
body('address')
.notEmpty().withMessage(_sr['fa'].required.address),
body('location')
.isObject().withMessage(`لوکیشن از نوع آبجکت می باشد`),
],
checkValidations(validationResult),
async (req, res) => {
const errors = validationResult(req)
if (!errors.isEmpty()) return res.status(422).json({validation: errors.mapped()})
try {
const {title, province, city, address, location} = req.body
const newAddress = {title, province, city, address, location, useRate: 1};
const targetUser = await User.findById(req?.user?._id);
if (!targetUser) return res404(res, `کاربر مورد نظر یافت نشد`)
for (const item of targetUser.addresses) {
item.used = false;
}
targetUser.addresses.push(newAddress)
await targetUser.save();
return res.json({message: _sr['fa'].response.success_save});
} catch (error) {
return res500(res, _sr['fa'].response.unknownError);
}
}
]
module.exports.update_user_address = [
[
body('title')
.optional().isString().withMessage(`فرمت عنوان از نوع رشته می باشد`),
body('province')
.notEmpty().withMessage(_sr['fa'].required.province),
body('city')
.notEmpty().withMessage(_sr['fa'].required.city),
// .bail()
// .custom((value, {req}) => {
// if (req.body.city.localeCompare('اراک') !== 0) return Promise.reject('آدرس خارج از محدوده مد نظر می باشد')
// else return true
// }),
body('address')
.notEmpty().withMessage(_sr['fa'].required.address),
body('location')
.isObject().withMessage(`لوکیشن از نوع آبجکت می باشد`),
],
checkValidations(validationResult),
(req, res) => {
User.findOne({'addresses._id': req?.params?.id}, (err, user) => {
if (err || !user) return res404(req, res)
const oldAddress = user.addresses.id(req?.params?.id)
oldAddress.remove()
const {title, province, city, address, location} = req.body
const newAddress = {title, province, city, address, location}
user.addresses.push(newAddress)
user.save(err => {
if (err) return res500(res, err)
else return res.json({message: _sr['fa'].response.success_save})
})
})
}
]
module.exports.update_user_address_by_admin = [
[
body('title')
.optional().isString().withMessage(`فرمت عنوان از نوع رشته می باشد`),
body('province')
.notEmpty().withMessage(_sr['fa'].required.province),
body('city')
.notEmpty().withMessage(_sr['fa'].required.city),
// .bail()
// .custom((value, {req}) => {
// if (req.body.city.localeCompare('اراک') !== 0) return Promise.reject('آدرس خارج از محدوده مد نظر می باشد')
// else return true
// }),
body('address')
.notEmpty().withMessage(_sr['fa'].required.address)
],
checkValidations(validationResult),
(req, res) => {
User.findOne({'addresses._id': req?.params?.id}, (err, user) => {
if (err || !user) return res404(req, res)
const targetAddress = user.addresses.id(req?.params?.id)
const {title, province, city, address} = req.body
targetAddress.title = title
targetAddress.province = province
targetAddress.city = city
targetAddress.address = address
user.save(err => {
if (err) return res500(res, err)
else return res.json({message: _sr['fa'].response.success_save})
})
})
}
]
module.exports.remove_user_address = [
(req, res) => {
User.findOne({'addresses._id': req?.params?.id}, (err, user) => {
if (err || !user) return res404(res, `کاربر مورد نظر یافت نشد`)
const oldAddress = user.addresses.id(req?.params?.id)
oldAddress.remove()
if (user.addresses.length && user.addresses.find(item => item.used !== true)) {
user.addresses[0].used = true;
user.addresses[0].useRate = user.addresses[0].useRate + 1;
}
user.save(err => {
if (err) return res500(res, _sr['fa'].response.unknownError)
else return res.json({message: _sr['fa'].response.success_remove})
})
})
}
]
module.exports.getAlladdress = [
async (req, res) => {
try {
const storeId = req.params.storeId
const user = await User.findById(req?.user?._id)
const addresses = [];
const getStoreInfo = await StoreInfo.findOne({_id : storeId})
const storeLocation = getStoreInfo?.location
if (!user) return res404(res, `کاربر مورد نظر پیدا نشد`);
for (const address of user.addresses) {
const newAddress = JSON.parse(JSON.stringify(address));
if (getStoreInfo) {
if (getStoreInfo?.shippingType) {
newAddress.cost = getStoreInfo?.shippingCost || 0
addresses.push(newAddress);
} else {
if (storeLocation) {
const lng = newAddress.location.coordinates[0]
const lat = newAddress.location.coordinates[1]
const storeLng = storeLocation.coordinates[0]
const storeLat = storeLocation.coordinates[1]
const getDistance = await axios.get(`https://map.ir/routes/route/v1/driving/${lng},${lat};${storeLng},${storeLat}`, {
headers: {
'x-api-key': apiKey
}
});
if (getDistance.data.code !== 'Ok') return res500(_sr['fa'].response.unknownError);
const distance =getDistance.data.routes[0].distance<=1000 ? 0 : Math.round(getDistance.data.routes[0].distance / 1000) || 0
newAddress.cost = distance * (getStoreInfo?.shippingCost || 0) || 0
addresses.push(newAddress)
} else {
newAddress.cost = 0
addresses.push(newAddress);
}
}
} else {
newAddress.cost = 0;
addresses.push(newAddress);
}
}
return res.json(addresses);
} catch (error) {
return res500(res, _sr['fa'].response.unknownError)
}
}
]
module.exports.setDefaultAddress = [
async (req, res) => {
try {
const checkAddress = await User.findOne({'addresses._id': req?.params?.id})
if (!checkAddress) return res404(res, `آدرس انتخاب شده وجود ندارد`)
for (const item of checkAddress.addresses) {
item.used = false;
}
let address = checkAddress.addresses.id(req?.params?.id)
address.used = true
address.useRate = address.useRate++
await checkAddress.save()
return res.json({message: _sr['fa'].response.success_save});
} catch (error) {
return res500(res, _sr['fa'].response.unknownError)
}
}
]
////////////// user comments
module.exports.getAllComments = [
async (req, res) => {
try {
const branchId = req?.params?.branchId
const comments = [];
const allComments = await Food.find({branchId , 'ratings.user_id': req.user._id})
.populate({path: 'ratings.user_id', select: 'first_name last_name'});
for (const comment of allComments) {
for (const item of comment.ratings) {
if (item?.user_id?._id.toString() === req?.user?._id.toString() && item.comment) {
comments.push(item)
}
}
}
return res.json(comments)
} catch (error) {
console.log(error.message)
return res500(res, _sr['fa'].response.unknownError);
}
}
]
/////////////////////////////////////////////////////////////////////// login (Admin)
module.exports.login = [
[
body('username')
.isLength({min: 4}).withMessage(_sr['fa'].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()}, {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)
],
(req, res) => {
const errors = validationResult(req)
if (!errors.isEmpty()) return res.status(422).json({validation: errors.mapped()})
const {deviceId, platform , fromWhere} = req.body
User.findOne({$or: [{email: req.body.username.toLowerCase()}, {username: req.body.username}]}, (err, user) => {
if (err || !user) return res404(res, err)
bcrypt.compare(req.body.password, user.password, async (err, isMatch) => {
if (err || !isMatch) return res.status(422).json({validation: {username: {msg: _sr['fa'].not_found.password}}})
if (user.token) {
jwt.verify(user.token.replace(/^Bearer\s/, ''), secretKey, async (err, decoded) => {
if (err) {
let token = await jwt.sign({_id: user._id}, secretKey, {expiresIn: req.body.remember_me ? '7d' : '1h'})
user.token = token
user.deviceId = deviceId
user.fromWhere = fromWhere
user.save(err => {
if (err) console.log(err)
return res.json({token: token})
})
} else {
user.deviceId = deviceId
user.platform = platform
user.fromWhere = fromWhere
user.save(err => {
if (err) console.log(err)
return res.json({token: user.token})
})
}
})
} else {
let token = await jwt.sign({_id: user._id}, secretKey, {expiresIn: req.body.remember_me ? '7d' : '1h'})
user.token = token
user.deviceId = deviceId
user.fromWhere = fromWhere
user.save(err => {
if (err) console.log(err)
return res.json({token: token})
})
}
})
})
}
]
/////////////////////////////////////////////////////////////////////// login (User)
module.exports.login_user = [
[
body('mobile_number')
.notEmpty().withMessage(_sr['fa'].required.phone_number)
.bail()
.isMobilePhone().withMessage(_sr['fa'].format.phone_number)
.bail()
.if((value, {req}) => {
return req.body.password && req.body.password.length >= 4
})
.custom((value, {req}) => {
return User.findOne({mobile_number: value})
.then(user => {
if (!user) return Promise.reject('کلمه عبور اشتباه است')
else return true
})
}),
body('password')
.notEmpty().withMessage(_sr['fa'].required.password)
.bail()
.isLength({min: 4}).withMessage(_sr['fa'].min_char.min4),
body('branchId')
.notEmpty().withMessage(_sr['fa'].required.field)
.bail()
.custom((value, {req}) => {
return StoreInfo.findOne({_id: value})
.then(store => {
if (!store) return Promise.reject(_sr['fa'].not_found.item_id)
else return true
})
})
],
checkValidations(validationResult),
(req, res) => {
const {branchId, deviceId, platform , fromWhere} = req.body
User.findOne({mobile_number: req.body.mobile_number}, (err, user) => {
if (err || !user) return res404(res, 'کلمه عبور اشتباه است')
bcrypt.compare(req.body.password, user.password, async (err, isMatch) => {
if (err || !isMatch) return res.status(422).json({validation: {password: {msg: 'کلمه عبور اشتباه است'}}})
let token = await jwt.sign({_id: user._id}, secretKey, {expiresIn: '1000d'})
user.token = token
user.deviceId = deviceId
user.platform = platform
user.fromWhere = fromWhere
if(!user.branches.includes(branchId)) user.branches.push(branchId)
user.save(err => {
if (err) console.log(err.message)
return res.json({token: token})
})
})
})
}
]
/////////////////////////////////////////////////////////////////////// logout (Admin)
module.exports.logout = [
(req, res) => {
const token = req.headers.authorization
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 (Admin)
// module.exports.getUser = [
// (req, res) => {
// const token = req?.headers?.authorization?.replace(/^Bearer\s/, '')
// if (token) {
// jwt.verify(token, secretKey, (err, decoded) => {
// if (err) return res.status(401).json({message: 'unauthenticated'})
// User.findById(decoded._id).select('-token -password').exec(async (err, user) => {
// if (err || !user) return res404(res, err)
// const clone = JSON.parse(JSON.stringify(user))
// try {
// clone.discount_codes = await DiscountCode.find({discount_user_id: user._id})
// return res.json({user: clone})
// } catch (e) {
// return res500(res, e)
// }
// })
// })
// } else {
// return res.status(401).json({message: 'unauthenticated'})
// }
// }
// ]
module.exports.getUser = [
async (req, res) => {
try {
const result = {}
const token = req?.headers?.authorization?.replace(/^Bearer\s/, '')
if (token) {
const decoded = await jwt.verify(token, secretKey)
if (decoded) {
const getUser = await User.findById(decoded._id).select('-token -password')
if (!getUser) return res404(res, `کاربر مورد نظر پیدا نشد`)
const clone = JSON.parse(JSON.stringify(getUser))
clone.discount_codes = await DiscountCode.find({discount_user_id: getUser._id})
result.user = clone
result.jobs = await Job.find()
return res.json(result)
} else {
res.status(401).json({message: 'unauthenticated'})
}
} else {
return res.status(401).json({message: 'unauthenticated'})
}
} catch (error) {
console.log(error.message)
return res500(res, _sr['fa'].response.unknownError)
}
}
]
module.exports.addFcmToken = [
async (req, res) => {
try {
const fcmToken = req.body.fcmToken
const admin = await User.findOne({_id: req.user._id, scope: 'admin'})
if (!admin) return res404(res, 'اطلاعات ادمین پیدا نشد با پشتیبانی تماس بگیرید')
admin.fcmToken = fcmToken
await admin.save()
return res.json({message: _sr['fa'].response.success_save})
} catch (error) {
return res500(res, _sr['fa'].response.unknownError)
}
}
]
module.exports.addFcmTokenUser = [
async (req, res) => {
try {
const {token, deviceId, platform, deviceName ,fromWhere} = req.body
const user = await User.findOne({_id: req.user._id, scope: 'user'})
if (!user) return res404(res, 'اطلاعات کاربر پیدا نشد با پشتیبانی تماس بگیرید')
user.fcmToken = token
user.deviceId = deviceId
user.platform = platform
user.fromWhere = fromWhere
user.deviceName = deviceName
await user.save()
return res.json({message: _sr['fa'].response.success_save})
} catch (error) {
return res500(res, _sr['fa'].response.unknownError)
}
}
]