diff --git a/package-lock.json b/package-lock.json index defda05..d81a987 100644 --- a/package-lock.json +++ b/package-lock.json @@ -38,6 +38,7 @@ "moment-jalaali": "^0.9.2", "mongoose": "^5.12.5", "mongoose-paginate-v2": "^1.3.18", + "morgan": "^1.10.0", "nodemailer": "^6.6.0", "nodemon": "^3.1.2", "nuxt": "^2.15.3", @@ -6293,6 +6294,24 @@ ], "license": "MIT" }, + "node_modules/basic-auth": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.1.2" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/basic-auth/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, "node_modules/bcryptjs": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", @@ -13299,6 +13318,34 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "license": "MIT" }, + "node_modules/morgan": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", + "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==", + "license": "MIT", + "dependencies": { + "basic-auth": "~2.0.1", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-finished": "~2.3.0", + "on-headers": "~1.0.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/morgan/node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/move-concurrently": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", diff --git a/package.json b/package.json index 4e6bd76..c48a291 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ "moment-jalaali": "^0.9.2", "mongoose": "^5.12.5", "mongoose-paginate-v2": "^1.3.18", + "morgan": "^1.10.0", "nodemailer": "^6.6.0", "nodemon": "^3.1.2", "nuxt": "^2.15.3", diff --git a/server/controllers/userController.js b/server/controllers/userController.js index 38e63f4..0884af3 100644 --- a/server/controllers/userController.js +++ b/server/controllers/userController.js @@ -1,23 +1,29 @@ -const User = require('../models/User'); -const {body, validationResult} = require('express-validator'); -const bcrypt = require('bcryptjs'); -const jwt = require('jsonwebtoken'); -const crypto = require('crypto'); -const sharp = require('sharp'); -const {secretKey} = require('./../authentication'); -const {_sr} = require('../plugins/serverResponses'); -const {res404, res500, hasWhiteSpaces, isLatinCharactersWithSymbol, generateRandomDigits} = require('../plugins/controllersHelperFunctions'); -const fs = require('fs'); -const nodemailer = require('nodemailer'); -const Category = require('../models/Category'); -const Logger = require('../models/Logger') +const User = require("../models/User"); +const { body, validationResult } = require("express-validator"); +const bcrypt = require("bcryptjs"); +const jwt = require("jsonwebtoken"); +const crypto = require("crypto"); +const sharp = require("sharp"); +const { secretKey } = require("./../authentication"); +const { _sr } = require("../plugins/serverResponses"); +const { + res404, + res500, + hasWhiteSpaces, + isLatinCharactersWithSymbol, + generateRandomDigits, +} = require("../plugins/controllersHelperFunctions"); +const fs = require("fs"); +const nodemailer = require("nodemailer"); +const Category = require("../models/Category"); +const Logger = require("../models/Logger"); ////// variables const profileWidth = 500; const profileHeight = 500; const profileQuality = 100; -const hostURL = 'localhost:6688'; +const hostURL = "localhost:6688"; const limit = 20; -const select = '-password -token'; +const select = "-password -token"; /** @todo add private to query */ @@ -25,160 +31,191 @@ const select = '-password -token'; /////////////////////////////////////////////////////////////////////// login module.exports.login = [ [ - body('username') - .if((value, {req}) => { - return req.body.password && req.body.password.length >= 4 - }) - .custom((value, {req}) => { - var test = value; - return User.findOne({username: value}) - .then(user => { - if (!user) return Promise.reject(_sr['fa'].not_found.password) - else return true - }) - }), + body("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("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) + 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()}) + const errors = validationResult(req); + if (!errors.isEmpty()) + return res.status(422).json({ validation: errors.mapped() }); try { - var {username, password, remember_me} = req.body; + 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}) + 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: `اکانت شما غیرفعال می باشد لطفا با ادمین تماس بگیرید`}); + return res.status(403).json({ + message: `اکانت شما غیرفعال می باشد لطفا با ادمین تماس بگیرید`, + }); } - const isMatch = await bcrypt.compare(password,user.password) + 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 { + if (logger) { + await Logger.findOneAndUpdate( + { user: user._id }, + { $set: { LastLogin: new Date() } }, + { new: true } + ); + } else { const newLogger = new Logger({ - user:user, - LastLogin:new Date() - }) + 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}); + 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'}); + 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}); + return res.json({ token: user.token }); } } else { - return res.status(422).json({validation: {username: {msg: _sr['fa'].not_found.password}}}); + 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}}}); + return res.status(422).json({ + validation: { username: { msg: _sr["fa"].not_found.password } }, + }); } } catch (error) { return res500(res, error?.message); } - } -] + }, +]; /////////////////////////////////////////////////////////////////////// logout module.exports.logout = [ async (req, res) => { - const token = req.headers.authorization?.replace(/^Bearer\s/, ''); + 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.'}) - }) + 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'}) + 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/, ''); + const token = req.headers.authorization?.replace(/^Bearer\s/, ""); // check if token is not destroyed - var user = await User.findOne({token: token}).select('-password'); + var user = await User.findOne({ token: token }).select("-password"); if (!user) { - return res.status(401).json({message: 'unauthorized'}); + return res.status(401).json({ message: "unauthorized" }); } if (!user.registration_done) { - return res.status(401).json({message: `اکانت شما غیرفعال می باشد لطفا با ادمین تماس بگیرید`}); + 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); + var checkToken = await jwt.verify( + user.token.replace(/^Bearer\s/, ""), + secretKey + ); if (!checkToken) { - return res.status(401).json({message: 'unauthorized'}); + return res.status(401).json({ message: "unauthorized" }); } - return res.json({user: user}); + return res.json({ user: user }); } catch (error) { - return res.status(401).json({message: 'unauthorized'}); + return res.status(401).json({ message: "unauthorized" }); } - } -] + }, +]; /** end auth --------------------------------------------- */ /////////////////////////////////////////////////////////////////////// admin module.exports.registerAdmin = [ [ - body('firstName') - .notEmpty().withMessage(_sr['fa'].required.first_name), + body("firstName").notEmpty().withMessage(_sr["fa"].required.first_name), - body('lastName') - .notEmpty().withMessage(_sr['fa'].required.last_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("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) @@ -193,95 +230,104 @@ module.exports.registerAdmin = [ // }) // }), - 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("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("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(`این فیلد باید از نوع آرایه باشد`); - } + 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) { + return Promise.reject(`شما باید یک دسترسی انتخاب کنید`); + } - if (permission.length && !permission.includes('superAdmin') && (!permission.includes('news') && !permission.includes('categories'))) { - return Promise.reject(`شما باید همراه با دسترسی مخصوص، دسترسی مدیریت صفحات یا اخبار را ارسال کنید`); - } else { - return true - } - }), + 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(`این فیلد باید از نوع آرایه باشد`); + } - body('specialPermissions') - .optional() - .custom((value, {req}) => { - var specialPermissions = _.isString(value) && !_.isEmpty(value) ? JSON.parse(value) : value; - if (!_.isArray(specialPermissions)) { - return Promise.reject(`این فیلد باید از نوع آرایه باشد`); - } + return true; + }), - return true - }), + body("portals").custom((value, { req }) => { + var portals = _.isString(value) ? JSON.parse(value) : value; + if (!_.isArray(portals)) { + return Promise.reject(`این فیلد باید از نوع آرایه باشد`); + } - 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(`شما باید محدوده دسترسی را مشخص کنید`); + } - if (!portals.length) { - return Promise.reject(`شما باید محدوده دسترسی را مشخص کنید`); - } + let isValid = portals.every((item) => { + return portal.includes(item); + }); - let isValid = portals.every((item) => { - return portal.includes(item); - }); + if (isValid) { + return true; + } else { + return Promise.reject(`${_sr["fa"].optional.onlyValid} => ${portal}`); + } + }), - if (isValid) { - return true; - } else { - return Promise.reject(`${_sr['fa'].optional.onlyValid} => ${portal}`); - } - }), - - body('registration_done') - .isBoolean().withMessage(_sr['fa'].format.boolean), + 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()}) + const errors = validationResult(req); + if (!errors.isEmpty()) + return res.status(422).json({ validation: errors.mapped() }); try { var { @@ -294,12 +340,16 @@ module.exports.registerAdmin = [ permissions, specialPermissions, registration_done, - portals + 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; + permissions = _.isString(permissions) + ? JSON.parse(permissions) + : permissions; + specialPermissions = _.isString(specialPermissions) + ? JSON.parse(specialPermissions) + : specialPermissions; portals = _.isString(portals) ? JSON.parse(portals) : portals; var data = { @@ -313,8 +363,10 @@ module.exports.registerAdmin = [ private: false, _creator: req.user?._id || null, _updatedBy: req.user?._id || null, - specialPermissions: permissions.includes('superAdmin') ? [] : specialPermissions, - portals: [...new Set(portals)] + specialPermissions: permissions.includes("superAdmin") + ? [] + : specialPermissions, + portals: [...new Set(portals)], }; /** @@ -322,23 +374,31 @@ module.exports.registerAdmin = [ */ 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}}}); + 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 + const imageName = + "user_" + + Date.now() + + "_" + + username + + "." + + image.mimetype.split("/")[1]; + data.profilePic = imageName; try { - const target = sharp(image.data) + const target = sharp(image.data); await target - .resize(profileWidth, profileHeight, { - fit: 'cover' - }) - .jpeg({ - quality: profileQuality - }) - .toFile(`./static/uploads/images/users/${imageName}`) + .resize(profileWidth, profileHeight, { + fit: "cover", + }) + .jpeg({ + quality: profileQuality, + }) + .toFile(`./static/uploads/images/users/${imageName}`); } catch (e) { - return res500(res, e?.message) + return res500(res, e?.message); } } @@ -374,14 +434,13 @@ module.exports.registerAdmin = [ * show result */ return res.status(201).json({ - message: _sr['fa'].response.success_save - }) - + message: _sr["fa"].response.success_save, + }); } catch (error) { return res500(res, error?.message); } - } -] + }, +]; /////////////////////////////////////////////////////////////////////// get user module.exports.getUserByAdmin = [ @@ -390,7 +449,9 @@ module.exports.getUserByAdmin = [ const userId = req.params.id; /** get one user */ - const user = await User.findById(userId).populate('specialPermissions').select(select); + const user = await User.findById(userId) + .populate("specialPermissions") + .select(select); /** if not exist show message to client */ if (!user) { @@ -399,42 +460,44 @@ module.exports.getUserByAdmin = [ /** 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}); + 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, `مشکلی در گرفتن اطلاعات پیش آمده لطفا دوباره تلاش کنید`); + return res500( + res, + `مشکلی در گرفتن اطلاعات پیش آمده لطفا دوباره تلاش کنید` + ); } /** show result */ return res.json(users); - } catch (error) { - return res500(res, error?.message); + return res500(res, error?.message); } - } -] + }, +]; module.exports.changeUserStatus = [ async (req, res) => { try { + const userId = req.params.id; - const userId = req.params.id - - let user = await User.findOne({private: false , _id : userId}); + let user = await User.findOne({ private: false, _id: userId }); if (!user) { return res404(res, `کاربر مورد نظر پیدا نشد`); @@ -445,13 +508,12 @@ module.exports.changeUserStatus = [ user.save(); /** show result */ - return res.json(_sr['fa'].response.success_save); - + return res.json(_sr["fa"].response.success_save); } catch (error) { return res500(res, `مشکلی در اجرای درخواست شما بوجود امده است`); } - } -] + }, +]; /////////////////////////////////////////////////////////////////////// delete one user module.exports.deleteOneUser = [ @@ -460,7 +522,7 @@ module.exports.deleteOneUser = [ const userId = req.params.id; /** get one user */ - const user = await User.findOne({_id: userId}); + const user = await User.findOne({ _id: userId }); /** if not exist show message to client */ if (!user) { @@ -468,7 +530,9 @@ module.exports.deleteOneUser = [ } if (user.private) { - return res.status(403).json({message: `شما نمیتوانید این کاربر را حذف کنید`}); + return res + .status(403) + .json({ message: `شما نمیتوانید این کاربر را حذف کنید` }); } /** @@ -489,98 +553,103 @@ module.exports.deleteOneUser = [ /** 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("firstName").notEmpty().withMessage(_sr["fa"].required.first_name), - body('lastName') - .notEmpty().withMessage(_sr['fa'].required.last_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("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(`این فیلد باید از نوع آرایه باشد`); - } + 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 (!permission.length) { + return Promise.reject(`شما باید یک دسترسی انتخاب کنید`); + } - if (specialPermissions.length !== 0 && !permission.includes('superAdmin') && (!permission.includes('news') && !permission.includes('categories'))) { - return Promise.reject(`شما باید همراه با دسترسی مخصوص، دسترسی مدیریت صفحات یا اخبار را ارسال کنید`); - } else { - return true - } - }), + 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(`این فیلد باید از نوع آرایه باشد`); + } - body('specialPermissions') - .optional() - .custom((value, {req}) => { - var specialPermissions = _.isString(value) && !_.isEmpty(value) ? JSON.parse(value) : value; - if (!_.isArray(specialPermissions)) { - return Promise.reject(`این فیلد باید از نوع آرایه باشد`); - } + return true; + }), - return true - }), + body("portals").custom((value, { req }) => { + var portals = _.isString(value) ? JSON.parse(value) : value; + if (!_.isArray(portals)) { + return Promise.reject(`این فیلد باید از نوع آرایه باشد`); + } - 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(`شما باید محدوده دسترسی را مشخص کنید`); + } - if (!portals.length) { - return Promise.reject(`شما باید محدوده دسترسی را مشخص کنید`); - } + let isValid = portals.every((item) => { + return portal.includes(item); + }); - let isValid = portals.every((item) => { - return portal.includes(item); - }); + if (isValid) { + return true; + } else { + return Promise.reject(`${_sr["fa"].optional.onlyValid} => ${portal}`); + } + }), - if (isValid) { - return true; - } else { - return Promise.reject(`${_sr['fa'].optional.onlyValid} => ${portal}`); - } - }), - - body('registration_done') - .isBoolean().withMessage(_sr['fa'].format.boolean), + 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()}) + const errors = validationResult(req); + if (!errors.isEmpty()) + return res.status(422).json({ validation: errors.mapped() }); try { const userId = req.params.id; @@ -593,12 +662,16 @@ module.exports.updateUser = [ permissions, specialPermissions, registration_done, - portals + 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; + permissions = _.isString(permissions) + ? JSON.parse(permissions) + : permissions; + specialPermissions = _.isString(specialPermissions) + ? JSON.parse(specialPermissions) + : specialPermissions; portals = _.isString(portals) ? JSON.parse(portals) : portals; /** get one user */ @@ -610,23 +683,31 @@ module.exports.updateUser = [ } if (!user.private && !req.user.private) { - return res.status(403).json({message: `شما نمیتوانید این کاربر را آپدیت کنید`}); + return res + .status(403) + .json({ message: `شما نمیتوانید این کاربر را آپدیت کنید` }); } /** check new email is dupllicate or not */ if (user.email !== email) { - var checkDupplicate = await User.find({email: email}); + var checkDupplicate = await User.find({ email: email }); if (checkDupplicate.length) { - return res.status(422).json({validation: {email: {msg: `${_sr['fa'].duplicated.email}`}}}); + 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}); + var checkDupplicate = await User.find({ mobileNumber: mobileNumber }); if (checkDupplicate.length) { - return res.status(422).json({validation: {mobileNumber: {msg: `${_sr['fa'].duplicated.phoneNumber}`}}}); + return res.status(422).json({ + validation: { + mobileNumber: { msg: `${_sr["fa"].duplicated.phoneNumber}` }, + }, + }); } } @@ -641,27 +722,37 @@ module.exports.updateUser = [ user._creator = req.user._id; user.username = user.username; user.permissions = permissions; - user.specialPermissions = permissions?.includes('superAdmin') ? [] : specialPermissions; + user.specialPermissions = permissions?.includes("superAdmin") + ? [] + : specialPermissions; user.private = user.private; - user.portals = [...new Set(portals)] + 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}}}); + 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]; + const imageName = + "user_" + + Date.now() + + "_" + + user.username + + "." + + image.mimetype.split("/")[1]; try { - const target = sharp(image.data) + const target = sharp(image.data); await target - .resize(profileWidth, profileHeight, { - fit: 'cover' - }) - .jpeg({ - quality: profileQuality - }) - .toFile(`./static/uploads/images/users/${imageName}`); + .resize(profileWidth, profileHeight, { + fit: "cover", + }) + .jpeg({ + quality: profileQuality, + }) + .toFile(`./static/uploads/images/users/${imageName}`); /** * if exist old pic delete it from file @@ -675,7 +766,6 @@ module.exports.updateUser = [ }); } } - } catch (e) { return res500(res, e?.message); } @@ -687,26 +777,27 @@ module.exports.updateUser = [ /** 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) - }), + 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 errors = validationResult(req); + if (!errors.isEmpty()) + return res.status(422).json({ validation: errors.mapped() }); try { const userId = req.params.id; @@ -722,7 +813,9 @@ module.exports.changePassword = [ } if (!user.private && !req.user.private) { - return res.status(403).json({message: `شما نمی توانید رمز عبور این کاربر را تغییر دهید`}); + return res + .status(403) + .json({ message: `شما نمی توانید رمز عبور این کاربر را تغییر دهید` }); } /** @@ -740,18 +833,17 @@ module.exports.changePassword = [ } user.password = hashPassword; - user.token = null + user.token = null; await user.save(); /** show result */ - return res.json({message: _sr['fa'].response.success_save}); - + return res.json({ message: _sr["fa"].response.success_save }); } catch (error) { res500(res, error?.message); } - } -] + }, +]; /////////////////////////////////////////////////////////////////////// get profile(get self) module.exports.getProfile = [ @@ -769,41 +861,33 @@ module.exports.getProfile = [ /** 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("firstName").notEmpty().withMessage(_sr["fa"].required.first_name), - body('lastName') - .notEmpty().withMessage(_sr['fa'].required.last_name), + body("lastName").notEmpty().withMessage(_sr["fa"].required.last_name), - body('mobileNumber') - .isNumeric().withMessage(_sr['fa'].format.number), + 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()}) + 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; + const { firstName, lastName, email, mobileNumber } = req.body; /** get one user */ var user = await User.findById(userId); @@ -815,18 +899,24 @@ module.exports.updateProfile = [ /** check new email is dupllicate or not */ if (user.email != email) { - var checkDupplicate = await User.find({email: email}); + var checkDupplicate = await User.find({ email: email }); if (checkDupplicate.length) { - return res.status(422).json({validation: {email: {msg: `${_sr['fa'].duplicated.email}`}}}); + 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}); + var checkDupplicate = await User.find({ mobileNumber: mobileNumber }); if (checkDupplicate.length) { - return res.status(422).json({validation: {mobileNumber: {msg: `${_sr['fa'].duplicated.phoneNumber}`}}}); + return res.status(422).json({ + validation: { + mobileNumber: { msg: `${_sr["fa"].duplicated.phoneNumber}` }, + }, + }); } } @@ -847,21 +937,29 @@ module.exports.updateProfile = [ /** 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}}}); + 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]; + const imageName = + "user_" + + Date.now() + + "_" + + user.username + + "." + + image.mimetype.split("/")[1]; try { - const target = sharp(image.data) + const target = sharp(image.data); await target - .resize(profileWidth, profileHeight, { - fit: 'cover' - }) - .jpeg({ - quality: profileQuality - }) - .toFile(`./static/uploads/images/users/${imageName}`); + .resize(profileWidth, profileHeight, { + fit: "cover", + }) + .jpeg({ + quality: profileQuality, + }) + .toFile(`./static/uploads/images/users/${imageName}`); /** * if exist old pic delete it from file @@ -875,7 +973,6 @@ module.exports.updateProfile = [ }); } } - } catch (e) { return res500(res, e?.message); } @@ -887,26 +984,27 @@ module.exports.updateProfile = [ /** 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) - }), + 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 errors = validationResult(req); + if (!errors.isEmpty()) + return res.status(422).json({ validation: errors.mapped() }); try { const userId = req.user._id; @@ -936,68 +1034,67 @@ module.exports.changePasswordProfile = [ } user.password = hashPassword; - user.token = null + user.token = null; await user.save(); /** show result */ - return res.json({message: _sr['fa'].response.success_save}); - + 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 - }) - }), + 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()}) + 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}); + 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'); - + 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(' + user: "recovery@rubynaturalco.com", + pass: "jd-m2?3ao?b(", }, tls: { - rejectUnauthorized: false - } - }) + rejectUnauthorized: false, + }, + }); const emailHTMLTemplate = `
${Date.now()} - ` + `; // send mail with defined transport object let info = await transporter.sendMail({ from: '"Ostandari Portal"