const User = require("../models/User"); const { body, validationResult } = require("express-validator"); const { rateLimit } = require("express-rate-limit"); const bcrypt = require("bcryptjs"); const jwt = require("jsonwebtoken"); const crypto = require("crypto"); const sharp = require("sharp"); const { secretKey } = require("./../authentication"); const { _sr } = require("../plugins/serverResponses"); const { res404, res500, hasWhiteSpaces, isLatinCharactersWithSymbol, generateRandomDigits, } = require("../plugins/controllersHelperFunctions"); const fs = require("fs"); const nodemailer = require("nodemailer"); const Category = require("../models/Category"); const Logger = require("../models/Logger"); const cacheService = require("../plugins/cache"); const { sms } = require("../plugins/sms"); ////// variables const profileWidth = 500; const profileHeight = 500; const profileQuality = 100; const hostURL = "localhost:6688"; const limit = 20; const select = "-password -token"; const limiter = rateLimit({ windowMs: 10 * 60 * 1000, // 10 minutes limit: 10, standardHeaders: "draft-7", legacyHeaders: false, }); /** @todo add private to query */ /** auth --------------------------------------------- */ /////////////////////////////////////////////////////////////////////// login module.exports.login = [ limiter, [ body("username") .if((value, { req }) => { return req.body.password && req.body.password.length >= 4; }) .custom((value, { req }) => { var test = value; return User.findOne({ username: value }).then((user) => { if (!user) return Promise.reject(_sr["fa"].not_found.password); else return true; }); }), body("password") .notEmpty() .withMessage(_sr["fa"].required.password) .bail() .isLength({ min: 4 }) .withMessage(_sr["fa"].min_char.min4), body("remember_me") .exists() .withMessage(_sr["fa"].required.remember_me) .bail() .isBoolean() .withMessage(_sr["fa"].format.boolean), ], async (req, res) => { const errors = validationResult(req); if (!errors.isEmpty()) return res.status(422).json({ validation: errors.mapped() }); try { var { username, password, remember_me } = req.body; /** get user */ var user = await User.findOne({ $or: [{ username: username }, { email: username }], }); const logger = await Logger.findOne({ user: user._id }); if (!user.registration_done) { return res.status(403).json({ message: `اکانت شما غیرفعال می باشد لطفا با ادمین تماس بگیرید`, }); } const isMatch = await bcrypt.compare(password, user.password); /**check user */ if (user) { /** check password */ if (isMatch) { if (logger) { await Logger.findOneAndUpdate( { user: user._id }, { $set: { LastLogin: new Date() } }, { new: true } ); } else { const newLogger = new Logger({ user: user, LastLogin: new Date(), }); await newLogger.save(); } /** if have token and it true show result else generate new token */ if (user.token) { jwt.verify( user.token.replace(/^Bearer\s/, ""), secretKey, async (err, decoeded) => { if (err || !decoeded) { /** generate new token */ var token = await jwt.sign({ _id: user._id }, secretKey, { expiresIn: remember_me ? "7d" : "1h", }); user.token = token; await user.save(); return res.json({ token: user.token }); } else { return res.json({ token: user.token }); } } ); } else { /** generate new token */ var token = await jwt.sign({ _id: user._id }, secretKey, { expiresIn: remember_me ? "7d" : "1h", }); user.token = token; await user.save(); return res.json({ token: user.token }); } } else { return res.status(422).json({ validation: { username: { msg: _sr["fa"].not_found.password } }, }); } } else { return res.status(422).json({ validation: { username: { msg: _sr["fa"].not_found.password } }, }); } } catch (error) { return res500(res, error?.message); } }, ]; /** otp --------------------------------------------- */ /////////////////////////////////////////////////////////////////////// otp module.exports.otp = [ limiter, [ body("phone") .notEmpty() .withMessage(_sr["fa"].required.phone_number) .bail() .isMobilePhone("fa-IR") .withMessage(_sr["fa"].required.phone_number), // .isLength({ min: 4 }) // .withMessage(_sr["fa"].min_char.min4), ], async (req, res) => { console.log("body", req.body); try { const errors = validationResult(req); if (!errors.isEmpty()) return res.status(422).json({ validation: errors.mapped() }); const { phone } = req.body; const user = await User.findOne({ mobileNumber: phone }); if (!user) return res.status(406).json({ message: "شماره موبایل نامعتبر می باشد", }); const existOtp = cacheService.get(`OTP:LOGIN:${phone}`); if (existOtp) return res.status(400).json({ message: "کد به شماره موبایل شما ارسال شده است", ttl: (cacheService.getTtl(`OTP:LOGIN:${phone}`) - Date.now()) / 1000, }); const otp = crypto.randomInt(10000, 99999); console.log("==> otp :", otp); const message = `کد ورود شما ${otp} میباشد. استانداری لغو11`; /** save otp in cache */ cacheService.set(`OTP:LOGIN:${phone}`, otp, 120); /** send sms to user */ const smsResult = await sms(phone, message); if (!smsResult.IsSuccessful) { console.log(smsResult); return res500(res, `مشکلی در ارسال پیامک پیش آمده است`); } return res.status(200).json({ message: "کد به شماره موبایل شما ارسال شد", }); } catch (error) { return res500(res, error?.message); } }, ]; /////////////////////////////////////////////////////////////////////// verify otp module.exports.verifyOtp = [ limiter, [ body("phone") .notEmpty() .withMessage(_sr["fa"].required.phone_number) .bail() .isMobilePhone("fa-IR") .withMessage(_sr["fa"].required.phone_number), body("code") .notEmpty() .withMessage(_sr["fa"].required.otp_code) .bail() .isLength({ min: 5, max: 5 }) .withMessage(_sr["fa"].format.otp_length), ], async (req, res) => { try { const errors = validationResult(req); if (!errors.isEmpty()) return res.status(422).json({ validation: errors.mapped() }); const { phone, code } = req.body; // Check if the OTP exists in the cache const cachedOtp = cacheService.get(`OTP:LOGIN:${phone}`); if (!cachedOtp) { return res.status(400).json({ message: "کد وارد شده منقضی شده است یا نامعتبر میباشد", }); } // Verify if the provided OTP matches the cached OTP if (cachedOtp.toString() !== code.trim()) { return res.status(422).json({ validation: { code: { msg: "کد وارد شده نامعتبر میباشد" } }, }); } // Find the user by phone number const user = await User.findOne({ mobileNumber: phone }); if (!user) { return res.status(406).json({ message: "شماره موبایل نامعتبر می باشد", }); } // Check if the user's registration is complete if (!user.registration_done) { return res.status(403).json({ message: `اکانت شما غیرفعال می باشد لطفا با ادمین تماس بگیرید`, }); } // Create or update login logger const logger = await Logger.findOne({ user: user._id }); if (logger) { await Logger.findOneAndUpdate( { user: user._id }, { $set: { LastLogin: new Date(), ip: req.ip } }, { new: true } ); } else { const newLogger = new Logger({ user: user, LastLogin: new Date(), }); await newLogger.save(); } // Check if the user already has a valid token if (user.token) { jwt.verify( user.token.replace(/^Bearer\s/, ""), secretKey, async (err, decoded) => { if (err || !decoded) { // Generate a new token if the existing one is invalid const token = await jwt.sign({ _id: user._id }, secretKey, { expiresIn: "2h", }); user.token = token; await user.save(); // Remove the OTP from the cache cacheService.del(`OTP:LOGIN:${phone}`); return res.json({ token: user.token }); } else { // Remove the OTP from the cache cacheService.del(`OTP:LOGIN:${phone}`); return res.json({ token: user.token }); } } ); } else { // Generate a new token if none exists const token = await jwt.sign({ _id: user._id }, secretKey, { expiresIn: "1h", }); user.token = token; await user.save(); // Remove the OTP from the cache cacheService.del(`OTP:LOGIN:${phone}`); return res.json({ token: user.token }); } } catch (error) { return res500(res, error?.message); } }, ]; /////////////////////////////////////////////////////////////////////// logout module.exports.logout = [ async (req, res) => { const token = req.headers.authorization?.replace(/^Bearer\s/, ""); if (token) { User.findOneAndUpdate( { token: token }, { token: null }, (err, oldData) => { if (err || !oldData) res.status(401).json({ message: "Your not logged in" }); else return res.json({ message: "You are logged out." }); } ); } else { return res.status(401).json({ message: "Your not logged in" }); } }, ]; /////////////////////////////////////////////////////////////////////// get user module.exports.getuser = [ async (req, res) => { const token = req.headers.authorization?.replace(/^Bearer\s/, ""); // check if token is not destroyed var user = await User.findOne({ token: token }).select("-password"); if (!user) { return res.status(401).json({ message: "unauthorized" }); } if (!user.registration_done) { return res.status(401).json({ message: `اکانت شما غیرفعال می باشد لطفا با ادمین تماس بگیرید`, }); } //verifies secret and checks if the token is expired try { var checkToken = await jwt.verify( user.token.replace(/^Bearer\s/, ""), secretKey ); if (!checkToken) { return res.status(401).json({ message: "unauthorized" }); } return res.json({ user: user }); } catch (error) { return res.status(401).json({ message: "unauthorized" }); } }, ]; /** end auth --------------------------------------------- */ /////////////////////////////////////////////////////////////////////// admin module.exports.registerAdmin = [ [ body("firstName").notEmpty().withMessage(_sr["fa"].required.first_name), body("lastName").notEmpty().withMessage(_sr["fa"].required.last_name), body("mobileNumber") .if((value, { req }) => { return req.body.mobileNumber; }) .custom((value, { req }) => { if (!_.isEmpty(value) && !lodash.isNumeric(value)) { return Promise.reject(_sr["fa"].format.number); } return User.findOne({ mobileNumber: value }).then((user) => { if (user) return Promise.reject(_sr["fa"].duplicated.phoneNumber); else return true; }); }), // body('email') // .optional().isEmail().withMessage(_sr['fa'].format.email) // .if((value, {req}) => { // return req.body.email // }) // .custom((value, {req}) => { // return User.findOne({email: value}) // .then(user => { // if (user) return Promise.reject(_sr['fa'].duplicated.email) // else return true // }) // }), body("username") .isLength({ min: 4 }) .withMessage(_sr["fa"].min_char.min4) .bail() .custom((value, { req }) => { if (hasWhiteSpaces(value)) return Promise.reject(_sr["fa"].response.whiteSpace); else return true; }) .bail() .custom((value, { req }) => { if (!isLatinCharactersWithSymbol(value)) return Promise.reject(_sr["fa"].response.latinChar); else return true; }) .bail() .custom((value, { req }) => { return User.findOne({ username: value }).then((user) => { if (user) return Promise.reject(_sr["fa"].duplicated.username); else return true; }); }), body("password") .isLength({ min: 4 }) .withMessage(_sr["fa"].min_char.min4) .custom((value, { req }) => { if (value === req.body.password_confirmation) return Promise.resolve(); else return Promise.reject(_sr["fa"].response.passwords_not_match); }), body("permissions") .if((value, { req }) => { return req.body.specialPermissions; }) .custom((value, { req }) => { var permission = _.isString(value) ? JSON.parse(value) : value; if (!_.isArray(permission)) { return Promise.reject(`این فیلد باید از نوع آرایه باشد`); } if (!permission.length) { return Promise.reject(`شما باید یک دسترسی انتخاب کنید`); } if ( permission.length && !permission.includes("superAdmin") && !permission.includes("news") && !permission.includes("categories") ) { return Promise.reject( `شما باید همراه با دسترسی مخصوص، دسترسی مدیریت صفحات یا اخبار را ارسال کنید` ); } else { return true; } }), body("specialPermissions") .optional() .custom((value, { req }) => { var specialPermissions = _.isString(value) && !_.isEmpty(value) ? JSON.parse(value) : value; if (!_.isArray(specialPermissions)) { return Promise.reject(`این فیلد باید از نوع آرایه باشد`); } return true; }), body("portals").custom((value, { req }) => { var portals = _.isString(value) ? JSON.parse(value) : value; if (!_.isArray(portals)) { return Promise.reject(`این فیلد باید از نوع آرایه باشد`); } if (!portals.length) { return Promise.reject(`شما باید محدوده دسترسی را مشخص کنید`); } let isValid = portals.every((item) => { return portal.includes(item); }); if (isValid) { return true; } else { return Promise.reject(`${_sr["fa"].optional.onlyValid} => ${portal}`); } }), body("registration_done").isBoolean().withMessage(_sr["fa"].format.boolean), ], async (req, res) => { const errors = validationResult(req); if (!errors.isEmpty()) return res.status(422).json({ validation: errors.mapped() }); try { var { username, password, firstName, lastName, email, mobileNumber, permissions, specialPermissions, registration_done, portals, } = req.body; /** this code fix problem with array in form data */ permissions = _.isString(permissions) ? JSON.parse(permissions) : permissions; specialPermissions = _.isString(specialPermissions) ? JSON.parse(specialPermissions) : specialPermissions; portals = _.isString(portals) ? JSON.parse(portals) : portals; var data = { username, firstName, lastName, email, mobileNumber, permissions, registration_done, private: false, _creator: req.user?._id || null, _updatedBy: req.user?._id || null, specialPermissions: permissions.includes("superAdmin") ? [] : specialPermissions, portals: [...new Set(portals)], }; /** * if we have pic upload to server */ if (req.files && req.files.profilePic) { const image = req.files.profilePic; if (!_sr.supportedImageFormats.includes(image.mimetype.split("/")[1])) { return res.status(422).json({ validation: { profilePic: { msg: _sr["fa"].format.image } }, }); } const imageName = "user_" + Date.now() + "_" + username + "." + image.mimetype.split("/")[1]; data.profilePic = imageName; try { const target = sharp(image.data); await target .resize(profileWidth, profileHeight, { fit: "cover", }) .jpeg({ quality: profileQuality, }) .toFile(`./static/uploads/images/users/${imageName}`); } catch (e) { return res500(res, e?.message); } } /** * generate salt */ var salt = bcrypt.genSaltSync(10); /** * hash password with salt */ var hashPassword = bcrypt.hashSync(password, salt); if (!hashPassword) { return res500(res, `error in hash`); } data.password = hashPassword; /** * create new admin */ const newAdmin = await User.create(data); /** * if we have error show him */ if (!newAdmin) { return res500(`error in register admin`); } /** * show result */ return res.status(201).json({ message: _sr["fa"].response.success_save, }); } catch (error) { return res500(res, error?.message); } }, ]; /////////////////////////////////////////////////////////////////////// get user module.exports.getUserByAdmin = [ async (req, res) => { try { const userId = req.params.id; /** get one user */ const user = await User.findById(userId) .populate("specialPermissions") .select(select); /** if not exist show message to client */ if (!user) { return res404(res, `کاربر مورد نظر پیدا نشد`); } /** show result */ return res.json(user); } catch (error) { res500(res, error?.message); } }, ]; /////////////////////////////////////////////////////////////////////// get all user module.exports.getAllUsers = [ async (req, res) => { try { /** get all user */ const users = await User.paginate( { private: false }, { page: req.query.page, limit, select } ); /** if not exist show message to client */ if (!users) { return res500( res, `مشکلی در گرفتن اطلاعات پیش آمده لطفا دوباره تلاش کنید` ); } /** show result */ return res.json(users); } catch (error) { return res500(res, error?.message); } }, ]; module.exports.changeUserStatus = [ async (req, res) => { try { const userId = req.params.id; let user = await User.findOne({ private: false, _id: userId }); if (!user) { return res404(res, `کاربر مورد نظر پیدا نشد`); } user.registration_done = !user.registration_done; user.save(); /** show result */ return res.json(_sr["fa"].response.success_save); } catch (error) { return res500(res, `مشکلی در اجرای درخواست شما بوجود امده است`); } }, ]; /////////////////////////////////////////////////////////////////////// delete one user module.exports.deleteOneUser = [ async (req, res) => { try { const userId = req.params.id; /** get one user */ const user = await User.findOne({ _id: userId }); /** if not exist show message to client */ if (!user) { return res404(res, `کاربر مورد نظر پیدا نشد`); } if (user.private) { return res .status(403) .json({ message: `شما نمیتوانید این کاربر را حذف کنید` }); } /** * if exist old pic delete it from file */ if (user.profilePic) { var oldPic = `./static${user.profilePic}`; if (fs.existsSync(oldPic)) { fs.unlink(oldPic, (err) => { if (err) return res500(res, err?.message); }); } } /** delete user */ await user.deleteOne(); /** show result */ return res.json(user); } catch (error) { res500(res, error?.message); } }, ]; /////////////////////////////////////////////////////////////////////// update user module.exports.updateUser = [ [ body("firstName").notEmpty().withMessage(_sr["fa"].required.first_name), body("lastName").notEmpty().withMessage(_sr["fa"].required.last_name), body("mobileNumber") .if((value, { req }) => { return req.body.mobileNumber; }) .custom((value, { req }) => { if (!_.isEmpty(value) && !lodash.isNumeric(value)) { return Promise.reject(_sr["fa"].format.number); } return true; }), // body('email') // .optional().isEmail().withMessage(_sr['fa'].format.email), body("permissions") .if((value, { req }) => { return req.body.specialPermissions; }) .custom((value, { req }) => { let permission = _.isString(value) ? JSON.parse(value) : value; let specialPermissions = _.isString(req.body.specialPermissions) ? JSON.parse(req.body.specialPermissions) : req.body.specialPermissions; if (!_.isArray(permission)) { return Promise.reject(`این فیلد باید از نوع آرایه باشد`); } if (!permission.length) { return Promise.reject(`شما باید یک دسترسی انتخاب کنید`); } if ( specialPermissions.length !== 0 && !permission.includes("superAdmin") && !permission.includes("news") && !permission.includes("categories") ) { return Promise.reject( `شما باید همراه با دسترسی مخصوص، دسترسی مدیریت صفحات یا اخبار را ارسال کنید` ); } else { return true; } }), body("specialPermissions") .optional() .custom((value, { req }) => { var specialPermissions = _.isString(value) && !_.isEmpty(value) ? JSON.parse(value) : value; if (!_.isArray(specialPermissions)) { return Promise.reject(`این فیلد باید از نوع آرایه باشد`); } return true; }), body("portals").custom((value, { req }) => { var portals = _.isString(value) ? JSON.parse(value) : value; if (!_.isArray(portals)) { return Promise.reject(`این فیلد باید از نوع آرایه باشد`); } if (!portals.length) { return Promise.reject(`شما باید محدوده دسترسی را مشخص کنید`); } let isValid = portals.every((item) => { return portal.includes(item); }); if (isValid) { return true; } else { return Promise.reject(`${_sr["fa"].optional.onlyValid} => ${portal}`); } }), body("registration_done").isBoolean().withMessage(_sr["fa"].format.boolean), ], async (req, res) => { const errors = validationResult(req); if (!errors.isEmpty()) return res.status(422).json({ validation: errors.mapped() }); try { const userId = req.params.id; var { firstName, lastName, email, mobileNumber, permissions, specialPermissions, registration_done, portals, } = req.body; /** this code fix problem with array in form data */ permissions = _.isString(permissions) ? JSON.parse(permissions) : permissions; specialPermissions = _.isString(specialPermissions) ? JSON.parse(specialPermissions) : specialPermissions; portals = _.isString(portals) ? JSON.parse(portals) : portals; /** get one user */ var user = await User.findById(userId); /** if not exist show message to client */ if (!user) { return res404(res, `کاربر مورد نظر پیدا نشد`); } if (!user.private && !req.user.private) { return res .status(403) .json({ message: `شما نمیتوانید این کاربر را آپدیت کنید` }); } /** check new email is dupllicate or not */ if (user.email !== email) { var checkDupplicate = await User.find({ email: email }); if (checkDupplicate.length) { return res.status(422).json({ validation: { email: { msg: `${_sr["fa"].duplicated.email}` } }, }); } } /** check new mobileNumber is dupllicate or not */ if (user.mobileNumber !== mobileNumber) { var checkDupplicate = await User.find({ mobileNumber: mobileNumber }); if (checkDupplicate.length) { return res.status(422).json({ validation: { mobileNumber: { msg: `${_sr["fa"].duplicated.phoneNumber}` }, }, }); } } user.firstName = firstName; user.lastName = lastName; user.password = user.password; user.scope = user.scope; user.token = user.token; user.mobileNumber = mobileNumber; user.email = email; user.registration_done = registration_done; user._creator = req.user._id; user.username = user.username; user.permissions = permissions; user.specialPermissions = permissions?.includes("superAdmin") ? [] : specialPermissions; user.private = user.private; user.portals = [...new Set(portals)]; if (req.files && req.files.profilePic) { const image = req.files.profilePic; if (!_sr.supportedImageFormats.includes(image.mimetype.split("/")[1])) { return res.status(422).json({ validation: { profilePic: { msg: _sr["fa"].format.image } }, }); } const imageName = "user_" + Date.now() + "_" + user.username + "." + image.mimetype.split("/")[1]; try { const target = sharp(image.data); await target .resize(profileWidth, profileHeight, { fit: "cover", }) .jpeg({ quality: profileQuality, }) .toFile(`./static/uploads/images/users/${imageName}`); /** * if exist old pic delete it from file */ if (user.profilePic) { var oldPic = `./static${user.profilePic}`; if (fs.existsSync(oldPic)) { fs.unlink(oldPic, (err) => { if (err) return res500(res, err?.message); }); } } } catch (e) { return res500(res, e?.message); } user.profilePic = imageName; } await user.save(); /** show result */ return res.json(user); } catch (error) { res500(res, error?.message); } }, ]; /////////////////////////////////////////////////////////////////////// change password module.exports.changePassword = [ [ body("password") .isLength({ min: 4 }) .withMessage(_sr["fa"].min_char.min4) .custom((value, { req }) => { if (value === req.body.password_confirmation) return Promise.resolve(); else return Promise.reject(_sr["fa"].response.passwords_not_match); }), ], async (req, res) => { const errors = validationResult(req); if (!errors.isEmpty()) return res.status(422).json({ validation: errors.mapped() }); try { const userId = req.params.id; const password = req.body.password; /** get one user */ var user = await User.findById(userId); /** if not exist show message to client */ if (!user) { return res404(res, `کاربر مورد نظر پیدا نشد`); } if (!user.private && !req.user.private) { return res .status(403) .json({ message: `شما نمی توانید رمز عبور این کاربر را تغییر دهید` }); } /** * generate salt */ var salt = bcrypt.genSaltSync(10); /** * hash password with salt */ var hashPassword = bcrypt.hashSync(password, salt); if (!hashPassword) { return res500(res, `error in hash`); } user.password = hashPassword; user.token = null; await user.save(); /** show result */ return res.json({ message: _sr["fa"].response.success_save }); } catch (error) { res500(res, error?.message); } }, ]; /////////////////////////////////////////////////////////////////////// get profile(get self) module.exports.getProfile = [ async (req, res) => { try { const userId = req.user._id; /** get one user */ const user = await User.findById(userId).select(select); /** if not exist show message to client */ if (!user) { return res404(res, `کاربر مورد نظر پیدا نشد`); } /** show result */ return res.json(user); } catch (error) { res500(res, error?.message); } }, ]; /////////////////////////////////////////////////////////////////////// update profile(get self) module.exports.updateProfile = [ [ body("firstName").notEmpty().withMessage(_sr["fa"].required.first_name), body("lastName").notEmpty().withMessage(_sr["fa"].required.last_name), body("mobileNumber").isNumeric().withMessage(_sr["fa"].format.number), // body('email') // .isEmail().withMessage(_sr['fa'].format.email), ], async (req, res) => { const errors = validationResult(req); if (!errors.isEmpty()) return res.status(422).json({ validation: errors.mapped() }); try { const userId = req.user._id; const { firstName, lastName, email, mobileNumber } = req.body; /** get one user */ var user = await User.findById(userId); /** if not exist show message to client */ if (!user) { return res404(res, `کاربر مورد نظر پیدا نشد`); } /** check new email is dupllicate or not */ if (user.email != email) { var checkDupplicate = await User.find({ email: email }); if (checkDupplicate.length) { return res.status(422).json({ validation: { email: { msg: `${_sr["fa"].duplicated.email}` } }, }); } } /** check new mobileNumber is dupllicate or not */ if (user.mobileNumber != mobileNumber) { var checkDupplicate = await User.find({ mobileNumber: mobileNumber }); if (checkDupplicate.length) { return res.status(422).json({ validation: { mobileNumber: { msg: `${_sr["fa"].duplicated.phoneNumber}` }, }, }); } } user.firstName = firstName; user.lastName = lastName; user.password = user.password; user.scope = user.scope; user.token = user.token; user.mobileNumber = mobileNumber; user.email = email; user.registration_done = user.registration_done; user._creator = req.user._id; user.username = user.username; user.permissions = user.permissions; user.specialPermissions = user.specialPermissions; user.private = user.private; /** if exist a picture */ if (req.files && req.files.profilePic) { const image = req.files.profilePic; if (!_sr.supportedImageFormats.includes(image.mimetype.split("/")[1])) { return res.status(422).json({ validation: { profilePic: { msg: _sr["fa"].format.image } }, }); } const imageName = "user_" + Date.now() + "_" + user.username + "." + image.mimetype.split("/")[1]; try { const target = sharp(image.data); await target .resize(profileWidth, profileHeight, { fit: "cover", }) .jpeg({ quality: profileQuality, }) .toFile(`./static/uploads/images/users/${imageName}`); /** * if exist old pic delete it from file */ if (user.profilePic) { var oldPic = `./static${user.profilePic}`; if (fs.existsSync(oldPic)) { fs.unlink(oldPic, (err) => { if (err) return res500(res, err?.message); }); } } } catch (e) { return res500(res, e?.message); } user.profilePic = imageName; } await user.save(); /** show result */ return res.json(user); } catch (error) { res500(res, error?.message); } }, ]; /////////////////////////////////////////////////////////////////////// change password (profile) module.exports.changePasswordProfile = [ [ body("password") .isLength({ min: 4 }) .withMessage(_sr["fa"].min_char.min4) .custom((value, { req }) => { if (value === req.body.password_confirmation) return Promise.resolve(); else return Promise.reject(_sr["fa"].response.passwords_not_match); }), ], async (req, res) => { const errors = validationResult(req); if (!errors.isEmpty()) return res.status(422).json({ validation: errors.mapped() }); try { const userId = req.user._id; const password = req.body.password; /** get one user */ var user = await User.findById(userId); /** if not exist show message to client */ if (!user) { return res404(res, `کاربر مورد نظر پیدا نشد`); } /** * generate salt */ var salt = bcrypt.genSaltSync(10); /** * hash password with salt */ var hashPassword = bcrypt.hashSync(password, salt); if (!hashPassword) { return res500(res, `مشکلی در تغییر پسورد پیش آمده است`); } user.password = hashPassword; user.token = null; await user.save(); /** show result */ return res.json({ message: _sr["fa"].response.success_save }); } catch (error) { res500(res, error?.message); } }, ]; /////////////////////////////////////////////////////////////////////// forget password generate token module.exports.forgetPassGenerateToken = [ [ body("email") .optional() .isEmail() .withMessage(_sr["fa"].format.email) .if((value, { req }) => { return req.body.email; }) .custom((value, { req }) => { return User.findOne({ email: value }).then((user) => { if (!user) return Promise.reject(_sr["fa"].not_found.email); else return true; }); }), ], async (req, res) => { const errors = validationResult(req); if (!errors.isEmpty()) return res.status(422).json({ validation: errors.mapped() }); try { const email = req.body.email; /** get one user */ var user = await User.findOne({ email: email }); /** if not exist show message to client */ if (!user) { return res404(res, `کابر مورد نظر پیدا نشد`); } const token = crypto.randomBytes(20).toString("hex"); ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// let transporter = nodemailer.createTransport({ host: "www.rubynaturalco.com", port: 587, secure: false, // true for 465, false for other ports auth: { user: "recovery@rubynaturalco.com", pass: "jd-m2?3ao?b(", }, tls: { rejectUnauthorized: false, }, }); const emailHTMLTemplate = `
`; // send mail with defined transport object let info = await transporter.sendMail({ from: '"Ostandari Portal"