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) } } ]