diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml deleted file mode 100644 index a6a5fdd..0000000 --- a/.github/workflows/deploy.yaml +++ /dev/null @@ -1,42 +0,0 @@ -name: Deploy Checker -on: - push: - branches: - - main -jobs: - deployment: - runs-on: ubuntu-latest - steps: - - name: Set up environment - run: | - echo "COMMIT_MESSAGE=$(echo '${{ github.event.head_commit.message }}' | jq -aRs .)" >> $GITHUB_ENV - - - name: Deploy Stage - uses: fjogeleit/http-request-action@v1 - with: - url: 'https://canary.discord.com/api/webhooks/1266738294226554953/xLG8rouRFIAJJGSgroDyjorzkh1vxn6b2QqlLM44Y1rONt8F0rGkAB5v5VKY1h_znQW6' - method: 'POST' - customHeaders: '{"Content-Type": "application/json"}' - data: '{ - "content": " Github push ${{ github.repository }} / ${{ github.event.head_commit.timestamp }} / ${{github.event.head_commit.author.name}}", - "embeds": [ - { - "title": "${{ github.repository }}", - "description": "Git checker", - "url": "http://github.com/${{ github.repository }}", - "color": 5814783, - "fields": [ - { - "name": "${{github.event.head_commit.author.name}}", - "value": ${{ env.COMMIT_MESSAGE }} - } - ], - "author": { - "name": "${{ github.actor }}" - }, - "timestamp": "${{ github.event.head_commit.timestamp }}" - } - ], - "username": "${{github.event.head_commit.author.name}}", - "attachments": [] - }' diff --git a/.github/workflows/liara.yaml b/.github/workflows/liara.yaml index 531ad93..59a5adb 100644 --- a/.github/workflows/liara.yaml +++ b/.github/workflows/liara.yaml @@ -7,14 +7,81 @@ jobs: deploy: runs-on: ubuntu-latest + env: + DISCORD_WEBHOOK_URL: 'https://canary.discord.com/api/webhooks/1266738294226554953/xLG8rouRFIAJJGSgroDyjorzkh1vxn6b2QqlLM44Y1rONt8F0rGkAB5v5VKY1h_znQW6' + LIARA_TOKEN: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySUQiOiI2NGVkY2ZmYWJiODUyOWZmNWFmOTU3YmEiLCJpYXQiOjE3MjAyNzUyNDB9.WNsgMX03tD1rZaceKRgjQ_MCffvW8oOQ7CnT_NdYP30 + APP_NAME: asanservice + steps: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: node-version: "18" + - name: Set up environment + run: | + echo "COMMIT_MESSAGE=$(echo '${{ github.event.head_commit.message }}' | jq -aRs .)" >> $GITHUB_ENV - name: update-liara - env: - LIARA_TOKEN: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySUQiOiI2NGVkY2ZmYWJiODUyOWZmNWFmOTU3YmEiLCJpYXQiOjE3MjAyNzUyNDB9.WNsgMX03tD1rZaceKRgjQ_MCffvW8oOQ7CnT_NdYP30 + run: | npm i -g @liara/cli@5 - liara deploy --app="asanservice" --api-token="$LIARA_TOKEN" --no-app-logs \ No newline at end of file + liara deploy --app="$APP_NAME" --api-token="$LIARA_TOKEN" --no-app-logs + - name: Deploy Stage + if: success() + uses: fjogeleit/http-request-action@v1 + with: + url: ${{ env.DISCORD_WEBHOOK_URL }} + method: 'POST' + customHeaders: '{"Content-Type": "application/json"}' + data: '{ + "content": " Github push ${{ github.repository }} / ${{ github.event.head_commit.timestamp }} / ${{github.event.head_commit.author.name}}", + "embeds": [ + { + "title": "${{ github.repository }}", + "description": "Success deploy", + "url": "http://github.com/${{ github.repository }}", + "color": 32768, + "fields": [ + { + "name": "${{github.event.head_commit.author.name}}", + "value": ${{ env.COMMIT_MESSAGE }} + } + ], + "author": { + "name": "${{ github.actor }}" + }, + "timestamp": "${{ github.event.head_commit.timestamp }}" + } + ], + "username": "${{github.event.head_commit.author.name}}", + "attachments": [] + }' + - name: Deploy Stage + if: failure() + uses: fjogeleit/http-request-action@v1 + with: + url: ${{ env.DISCORD_WEBHOOK_URL }} + method: 'POST' + customHeaders: '{"Content-Type": "application/json"}' + data: '{ + "content": " Failed to deploy ${{ github.repository }} / ${{ github.event.head_commit.timestamp }} / ${{github.event.head_commit.author.name}}", + "embeds": [ + { + "title": "${{ github.repository }}", + "description": "Failed to deploy", + "url": "http://github.com/${{ github.repository }}", + "color": 16711680, + "fields": [ + { + "name": "${{github.event.head_commit.author.name}}", + "value": ${{ env.COMMIT_MESSAGE }} + } + ], + "author": { + "name": "${{ github.actor }}" + }, + "timestamp": "${{ github.event.head_commit.timestamp }}" + } + ], + "username": "${{github.event.head_commit.author.name}}", + "attachments": [] + }' \ No newline at end of file diff --git a/bun.lockb b/bun.lockb new file mode 100644 index 0000000..55c24e2 Binary files /dev/null and b/bun.lockb differ diff --git a/package-lock.json b/package-lock.json index 07f9bd4..4e0da68 100644 --- a/package-lock.json +++ b/package-lock.json @@ -38,6 +38,7 @@ "nuxt-leaflet": "^0.0.27", "read-excel-file": "^5.2.2", "socket.io": "^4.4.1", + "validator": "^13.12.0", "vue-persian-datetime-picker": "^2.10.3" }, "devDependencies": { @@ -20668,9 +20669,9 @@ } }, "node_modules/validator": { - "version": "13.11.0", - "resolved": "https://registry.npmjs.org/validator/-/validator-13.11.0.tgz", - "integrity": "sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ==", + "version": "13.12.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.12.0.tgz", + "integrity": "sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg==", "engines": { "node": ">= 0.10" } diff --git a/package.json b/package.json index be9cd69..d835fa0 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ "nuxt-leaflet": "^0.0.27", "read-excel-file": "^5.2.2", "socket.io": "^4.4.1", + "validator": "^13.12.0", "vue-persian-datetime-picker": "^2.10.3" }, "devDependencies": { diff --git a/server/WebSocket/controllers/admin_EventsController.js b/server/WebSocket/controllers/admin_EventsController.js index 458a01a..da300e8 100644 --- a/server/WebSocket/controllers/admin_EventsController.js +++ b/server/WebSocket/controllers/admin_EventsController.js @@ -7,11 +7,15 @@ const OldPieceRequest = require('../../models/OldPieceRequest') const BufferRequest = require('../../models/BufferRequest') const GuaranteeReport = require('../../models/GuaranteeReport') const Complaint = require('../../models/Complaint') - +const Withdraw = require('../../models/GPS.Withdraw'); +const RequestGPS = require('../../models/GPS.Request') +const AwardRequest = require('../../models/GPS.AwardRequest'); +const InstalledDevice = require('../../models/GPS.InstalledDevice'); module.exports.getAllNotifs = async socket => { try { const allData = await Promise.all([ + // unreadCuMsgs ContactPageMessage.countDocuments({ read: false }), @@ -36,7 +40,19 @@ module.exports.getAllNotifs = async socket => { // newGuaranteeReports GuaranteeReport.countDocuments({ status: 'sent', seen: false }), - Complaint.countDocuments({ read: false }) + Complaint.countDocuments({ read: false }), + + // unread withdraw request + Withdraw.countDocuments({ status: 0 }), + + // unread GPS request + RequestGPS.countDocuments({ status: 0 }), + + // unread award request + AwardRequest.countDocuments({ status: 0 }), + + // unread install device request + InstalledDevice.countDocuments({ status: 0 }) ]) const unreadCuMsgs = allData[0] @@ -48,6 +64,10 @@ module.exports.getAllNotifs = async socket => { const newBufferRequests = allData[6] const newGuaranteeReports = allData[7] const newComplaintReports = allData[8] + const newWithdrawRequest = allData[9] + const newGpsRequest = allData[10] + const newAwardRequest = allData[11] + const newInstallDeviceRequest = allData[12] socket.emit(`admin:allNotifs`, { @@ -59,7 +79,11 @@ module.exports.getAllNotifs = async socket => { newOldPieceRequests, newBufferRequests, newGuaranteeReports, - newComplaintReports + newComplaintReports, + newWithdrawRequest, + newGpsRequest, + newAwardRequest, + newInstallDeviceRequest }) } catch (e) { console.log(e) diff --git a/server/_env.js b/server/_env.js index f2fea60..1d75de1 100644 --- a/server/_env.js +++ b/server/_env.js @@ -1,6 +1,7 @@ const EnvirementVariables = { // node envirements - isDev: process.env.NODE_ENV === 'development', + // isDev: process.env.NODE_ENV === 'development', + isDev: true, isProduction: process.env.NODE_ENV === 'production', // server ports diff --git a/server/authentication.js b/server/authentication.js index 7bbf587..1289045 100644 --- a/server/authentication.js +++ b/server/authentication.js @@ -25,13 +25,31 @@ const authentication = { async isAdmin(req, res, next) { try { const token = req.headers?.authorization - if (!token) throw new Error('err') + if (!token) throw new Error('err1') const decoded = jwt.verify(token.replace(/^Bearer\s/, ''), authentication.secretKey) - if (!decoded) throw new Error('err') + if (!decoded) throw new Error('err2') const user = await User.findById(decoded._id) - if (!user || !user.scope.includes('admin')) throw new Error('err') + if (!user || !user.scope.includes('admin')) throw new Error('err3') + + req.user_id = decoded._id + return next() + } catch (err) { + return res401(res, 'unauthorized') + } + }, + // check if admin logged in (middleware) + async isGPS(req, res, next) { + try { + const token = req.headers?.authorization + if (!token) throw new Error('err1') + + const decoded = jwt.verify(token.replace(/^Bearer\s/, ''), authentication.secretKey) + if (!decoded) throw new Error('err2') + + const user = await User.findById(decoded._id) + if (!user || !user.scope.includes('gps')) throw new Error('err3') req.user_id = decoded._id return next() @@ -54,6 +72,7 @@ const authentication = { req.user_id = decoded._id return next() } catch (err) { + return res401(res, 'unauthorized') } }, diff --git a/server/constants.js b/server/constants.js new file mode 100644 index 0000000..6ba4bcb --- /dev/null +++ b/server/constants.js @@ -0,0 +1,10 @@ +exports.constants = { + VALIDATION_ERROR: 400, + UNAUTHORIZED: 401, + FORBIDOEN: 403, + NOT_FOUND: 404, + SERVER_ERROR: 500, + SITE_UNAUTHORIZED: 422, + TOO_MANY: 429, + Method_Not_Allowed:405 +}; diff --git a/server/controllers/GPS.Auth.js b/server/controllers/GPS.Auth.js new file mode 100644 index 0000000..16b1e3b --- /dev/null +++ b/server/controllers/GPS.Auth.js @@ -0,0 +1,64 @@ +const bcrypt = require('bcryptjs') +const jwt = require('jsonwebtoken') +const { body, validationResult } = require('express-validator') +const { secretKey } = require('../authentication') +const { _sr } = require('../plugins/serverResponses') +const { checkValidations } = require('../plugins/controllersHelperFunctions') +const User = require('../models/User') + +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().trim() }, { national_code: value }, { 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) + ], + checkValidations(validationResult), + async (req, res) => { + try { + const { username, password } = req.body + const user = await User.findOne({ + $or: [{ email: username.toLowerCase().trim() }, { national_code: username }, { username }] + }) + if (!user) throw new Error(_sr.fa.not_found.password) + const passwordMatch = await bcrypt.compare(password, user.password) + if (!passwordMatch) throw new Error(_sr.fa.not_found.password) + const token = await jwt.sign({ _id: user._id }, secretKey, { + expiresIn: req.body.remember_me ? '30d' : '7d' + }) + if(!user.scope.includes('gps')){ + throw new Error('شما به این بخش دسترسی ندارید') + } + user.token = token + await user.save() + return res.status(200).json({ token }) + } catch (err) { + return res.status(422).json({ + validation: { username: { msg: err.message } } + }) + } + } + ] \ No newline at end of file diff --git a/server/controllers/GPS.Award.js b/server/controllers/GPS.Award.js new file mode 100644 index 0000000..54c83b5 --- /dev/null +++ b/server/controllers/GPS.Award.js @@ -0,0 +1,84 @@ +const { body, validationResult, param } = require('express-validator'); +const { _sr } = require('../plugins/serverResponses'); +const { checkValidations } = require('../plugins/controllersHelperFunctions'); +const Award = require('../models/GPS.Award'); + + +module.exports.createAward = [ + [ + body('score').notEmpty().isInt().withMessage(_sr.fa.required.field), + body('title').notEmpty().isString().withMessage(_sr.fa.required.field), + body('desc').notEmpty().isString().withMessage(_sr.fa.required.field), + body('expireDate').notEmpty().withMessage(_sr.fa.required.field), + ], + checkValidations(validationResult), + async (req, res) => { + const { score, title, desc, expireDate } = req.body; + const fixDate = new Date(expireDate) + const award = await Award.create({ score, title, desc, expireDate:fixDate }) + res.status(201).json({ + msg: _sr.fa.response.success_save, + data: award + }) + + } +] + + +module.exports.findAllUser = async (req, res) => { + const toDay = new Date() + const data = await Award.find({expireDate: {$gt: toDay}}) + res.status(200).json(data) +} + +module.exports.findAllAdmin = async (req, res) => { + const data = await Award.find({}) + res.status(200).json(data) +} + +module.exports.findOne = [ + [ + param('id').notEmpty().isMongoId().withMessage('ایدی را وارد یا تصحیح کنید') + ], + checkValidations(validationResult), + async (req, res) => { + const data = await Award.findById(req.params.id) + if (!data) { + res.status(404).json({ msg: _sr.fa.not_found.item_id }) + } else { + res.status(200).json(data) + } + + } +] + +module.exports.update =[ + [ + param('id').notEmpty().isMongoId().withMessage('ایدی را وارد یا تصحیح کنید'), + body('score').notEmpty().isInt().withMessage(_sr.fa.required.field), + body('title').notEmpty().isString().withMessage(_sr.fa.required.field), + body('desc').notEmpty().isString().withMessage(_sr.fa.required.field), + body('expireDate').notEmpty().withMessage(_sr.fa.required.field), + ], + checkValidations(validationResult), + async (req, res) => { + const { score, title, desc, expireDate } = req.body; + const data = await Award.findById(req.params.id) + if (!data) { + res.status(404).json({ msg: _sr.fa.not_found.item_id }) + } else { + data.score = score; + data.title = title; + data.desc = desc; + data.expireDate = new Date(expireDate) + data.save() + res.status(200).json({ + msg: _sr.fa.response.success_save, + data + }) + } + + } +] + + diff --git a/server/controllers/GPS.AwardRequest.js b/server/controllers/GPS.AwardRequest.js new file mode 100644 index 0000000..cdeda43 --- /dev/null +++ b/server/controllers/GPS.AwardRequest.js @@ -0,0 +1,93 @@ +const { body, param, validationResult } = require('express-validator') +const { _sr } = require('../plugins/serverResponses') +const { checkValidations } = require('../plugins/controllersHelperFunctions') +const User = require('../models/User') +const Award = require('../models/GPS.Award'); +const AwardRequest = require('../models/GPS.AwardRequest'); + + +module.exports.sendRequest = [ + [ + body('awardId').notEmpty().isMongoId().withMessage(_sr.fa.required.field) + ], + checkValidations(validationResult), + async(req, res)=>{ + const award = await Award.findById(req.body.awardId) + if (!award) { + res.status(404).json({ msg: _sr.fa.not_found.item_id }) + }else if(award.expireDate < new Date()){ + res.status(404).json({ msg: _sr.fa.not_found.item_id }) + }else{ + const user = await User.findById(req.user_id) + if(award.score <= user.score){ + user.score -= award.score; + user.save() + const data = await AwardRequest.create({ + awardId:req.body.awardId, + userId:req.user_id + }) + res.status(200).json({ msg:_sr.fa.response.success_save, data}) + }else{ + res.status(400).json({ msg: "امتیاز شما برای این مورد کافی نیست" }) + + } + + } + + } +] + +module.exports.findAllUser = async(req, res)=>{ + const data = await AwardRequest.find({userId:req.user_id}).populate('awardId','-created_at -updated_at') + res.status(200).json(data) +} + +module.exports.findAllAdmin = async(req, res)=>{ + const data = await AwardRequest.find().populate('awardId','-created_at -updated_at').populate('userId', 'first_name last_name shopName shopNumber shopAddress national_code mobile_number') + res.status(200).json(data) +} + +module.exports.findOne = [ + [ + param('id').notEmpty().isMongoId().withMessage('ایدی را وارد یا تصحیح کنید') + ], + checkValidations(validationResult), + async (req, res) => { + const data = await AwardRequest.findById(req.params.id).populate('awardId','-created_at -updated_at').populate('userId', 'first_name last_name shopName shopNumber shopAddress national_code mobile_number') + if (!data) { + res.status(404).json({ msg: _sr.fa.not_found.item_id }) + } else { + res.status(200).json(data) + } + + } +] + + +module.exports.update = [ + [ + param('id').notEmpty().isMongoId().withMessage('ایدی را وارد یا تصحیح کنید'), + body('status').notEmpty().isInt().withMessage(_sr.fa.required.field), + body('desc').notEmpty().isString().withMessage(_sr.fa.required.field) + ], + checkValidations(validationResult), + async (req, res) => { + const { status, desc, metaData } = req.body; + const data = await AwardRequest.findById(req.params.id) + if (!data) { + res.status(404).json({ msg: _sr.fa.not_found.item_id }) + } else { + await AwardRequest.updateOne( + {id:req.params.id}, + { + status, + desc, + metaData + } + ) + res.status(200).json({ msg: _sr.fa.response.success_save }) + + } + + } +] diff --git a/server/controllers/GPS.BankAccount.js b/server/controllers/GPS.BankAccount.js new file mode 100644 index 0000000..56855c5 --- /dev/null +++ b/server/controllers/GPS.BankAccount.js @@ -0,0 +1,70 @@ +const { body, param, validationResult } = require('express-validator') +const { _sr } = require('../plugins/serverResponses') +const { checkValidations } = require('../plugins/controllersHelperFunctions') +const User = require('../models/User') + +module.exports.addCard = [ + [ + body('holderName').notEmpty().isString().withMessage(_sr.fa.required.name), + body('PAN').notEmpty().isInt().withMessage(_sr.fa.required.store_number), + body('IBAN').notEmpty().isIBAN().withMessage(_sr.fa.required.address) + ], + checkValidations(validationResult), + async (req, res) => { + try { + const { holderName, PAN, IBAN } = req.body; + const userData = await User.findById(req.user_id).select('id cardBank') + if (userData?.cardBank && Array.isArray(userData?.cardBank)) { + userData.cardBank.push({ + holderName, + PAN, + IBAN + }) + userData.save() + res.status(201).json({ msg: 'با موفقیت ثبت شد ' }) + } else { + userData.cardBank = [{ + holderName, + PAN, + IBAN + }]; + userData.save() + res.status(201).json({ msg: 'با موفقیت ثبت شد ' }) + } + } catch (error) { + res.status(500).json({ msg: error }) + + } + } +] + + +module.exports.getAll = [ + async (req, res) => { + const userData = await User.findById(req.user_id).select('id cardBank') + res.status(200).json(userData) + } +] + + +module.exports.deleteCard = [ + [ + param('id').notEmpty().isMongoId().withMessage('این ایدی اشتباه می باشد') + ], + checkValidations(validationResult), + async (req, res) => { + const userData = await User.findOneAndUpdate( + { + _id: req.user_id, + "cardBank._id": req.params.id + }, + { + $pull: { + cardBank: { _id: req.params.id } + } + }, + { new:true } + ).select('id cardBank') + res.status(200).json({ msg: "با موفقیت حذف شد ", data: userData }) + } +] \ No newline at end of file diff --git a/server/controllers/GPS.Device.js b/server/controllers/GPS.Device.js new file mode 100644 index 0000000..4167d01 --- /dev/null +++ b/server/controllers/GPS.Device.js @@ -0,0 +1,171 @@ +const readXlsxFile = require('read-excel-file/node') +const validator = require('validator') +const { body, param, validationResult } = require('express-validator'); +const { _sr } = require('../plugins/serverResponses'); +const { checkValidations, res500 } = require('../plugins/controllersHelperFunctions'); +const Device = require('../models/GPS.Device'); + +module.exports.addCode = [ + [ + body('model').notEmpty().isString().withMessage(_sr.fa.required.name), + body('IMEI').notEmpty().isIMEI().trim().withMessage('لطفا IMEI را وارد یا تصحیح کنید').custom(async (v) => { + const device = await Device.findOne({ IMEI: v }) + if (device) { + return Promise.reject(_sr.fa.duplicated.IMEI) + } else { + return true + } + }), + body('tomanPrice').notEmpty().isInt({ min: 0 }).withMessage("قیمت دستگاه را به تومتن وارد کنید"), + body('dollarProfit').notEmpty().isInt({ min: 0 }).withMessage("سود نصاب را به دلار وارد کنید"), + body('profit').notEmpty().isInt({ min: 0 }).withMessage("سود نصاب را به تومان وارد کنید"), + body('score').notEmpty().isInt({ min: 0 }).withMessage("امتیاز دریافتی نصاب را وارد کنید"), + body('renewalProfit').notEmpty().isInt({ min: 0 }).withMessage("سود دریافتی نصاب را از تمدید اشتراک وارد کنید"), + ], + checkValidations(validationResult), + async (req, res) => { + const data = await Device.create(req.body) + res.status(201).json({ msg: _sr.fa.response.success_save, data }) + } +] + + + +module.exports.importExel = async (req, res) => { + try { + if (!req.files?.file) return res.status(422).json({ validation: { file: { msg: 'فایل را اضافه کنید' } } }) + if (!req.files?.file.name.split('.').some(item => ['xlsx', 'xltx', 'xlsm', 'xlsb'].includes(item))) return res.status(422).json({ validation: { file: { msg: 'فرمت فایل درست نمیباشد' } } }) + const file = req.files.file + + const exelFile = await readXlsxFile(Buffer.from(file.data)); + const data = await creator(exelFile) + res.status(201).json({ msg: _sr.fa.response.success_save, data }) + + + } catch (error) { + console.log(error); + res500(res, error) + } + +} + +module.exports.getAll = [ + async (req, res) => { + let page; + let rows; + if (!req.query?.rows) { + rows = 10 + } else { + rows = req.query.rows + } + if (!req.query?.page) { + page = 0 + // eslint-disable-next-line eqeqeq + } else if (!req.query.page == 1) { + page = 0 + } else { + page = req.query.page + page = page * rows - rows + } + const data = await Device.find().sort({ created_at: -1 }).skip(page).limit(rows); + const total = Math.ceil((await Device.estimatedDocumentCount())) + res.status(200).json({ data, total }) + } +] + +module.exports.getOne = [ + [ + param('id').notEmpty().isMongoId().withMessage('ایدی اشتباه است') + ], + checkValidations(validationResult), + async (req, res) => { + const data = await Device.findById(req.params.id).sort({ created_at: -1 }) + if (!data) { + res.status(404).json(_sr.fa.not_found.item_id) + } else { + res.status(200).json(data) + } + + } +] + +module.exports.getOneByIMEI = [ + [ + param('imei').notEmpty().isString().withMessage('ایدی اشتباه است') + ], + checkValidations(validationResult), + async (req, res) => { + const data = await Device.findOne({IMEI:req.params.imei}).sort({ created_at: -1 }) + if (!data) { + res.status(404).json(_sr.fa.not_found.item_id) + } else { + res.status(200).json(data) + } + + } +] + + + +module.exports.updateDevice = [ + [ + param('id').notEmpty().isMongoId().withMessage('ایدی اشتباه است').custom(async (v) => { + const device = await Device.findById(v) + if (device) { + return true + } else { + return Promise.reject(_sr.fa.not_found.item_id) + + } + }), + body('model').notEmpty().isString().withMessage(_sr.fa.required.name), + body('tomanPrice').notEmpty().isInt({ min: 0 }).withMessage("قیمت دستگاه را به تومتن وارد کنید"), + body('dollarProfit').notEmpty().isInt({ min: 0 }).withMessage("سود نصاب را به دلار وارد کنید"), + body('profit').notEmpty().isInt({ min: 0 }).withMessage("سود نصاب را به تومان وارد کنید"), + body('score').notEmpty().isInt({ min: 0 }).withMessage("امتیاز دریافتی نصاب را وارد کنید"), + body('renewalProfit').notEmpty().isInt({ min: 0 }).withMessage("سود دریافتی نصاب را از تمدید اشتراک وارد کنید"), + + ], + checkValidations(validationResult), + async (req, res) => { + const { model, tomanPrice, dollarProfit, profit, score, renewalProfit } = req.body; + const data = await Device.findByIdAndUpdate( + req.params.id, + { + model, tomanPrice, dollarProfit, profit, score, renewalProfit + }, + { new: true } + ) + res.status(200).json({ msg: _sr.fa.response.success_save, data }) + } +] + + +const creator = (exel) => { + return new Promise(async (resolve, reject) => { + for (const row of exel) { + // eslint-disable-next-line no-constant-condition + if (validator.isIMEI(row[0].toString().trim()) || true) { + const device = await Device.findOne({ IMEI: row[0] }) + if (device) { + console.warn("Repeated IMEI ", row[0]) + } else { + await Device.create( + { + IMEI: row[0], + model: row[1], + tomanPrice: row[2], + dollarProfit: row[3] || 1, + profit: row[4] || 1, + score: row[5] || 1, + renewalProfit: row[6] || 1 + } + ) + } + } else { + console.warn("Wrong IMEI ", row[0]) + } + } + resolve("end") + }) +} \ No newline at end of file diff --git a/server/controllers/GPS.InstalledDevice.js b/server/controllers/GPS.InstalledDevice.js new file mode 100644 index 0000000..57b2118 --- /dev/null +++ b/server/controllers/GPS.InstalledDevice.js @@ -0,0 +1,160 @@ +const { body, param, validationResult } = require('express-validator'); +const { _sr } = require('../plugins/serverResponses'); +const { checkValidations } = require('../plugins/controllersHelperFunctions'); +const User = require('../models/User'); +const InstalledDevice = require('../models/GPS.InstalledDevice'); +const Device = require('../models/GPS.Device'); +const Score = require('../models/GPS.Score'); + +module.exports.deviceRegistration = [ + [ + body('IMEI').notEmpty().isString().withMessage('لطفا IMEI را وارد یا تصحیح کنید') + ], + checkValidations(validationResult), + async (req, res) => { + const device = await Device.findOne({ IMEI: req.body.IMEI }); + if (!device) { + throw res.status(404).json({ msg: 'این IMEI وجود ندارد' }) + // eslint-disable-next-line eqeqeq + } else if (device.status == 1) { + throw res.status(404).json({ msg: 'این IMEI قبلا ثبت شده' }) + + } else { + const data = { + deviceId: device.id, + status: 0, + registerDate: new Date(), + userId: req.user_id, + IMEI: req.body.IMEI + } + const newRequest = await InstalledDevice.create(data); + device.status = 1; + device.save() + res.status(201).json({ msg: _sr.fa.response.success_save, data: newRequest }) + } + } +] + + +module.exports.getAllForUser = async (req, res) => { + let page; + let rows; + if (!req.query?.rows || req.query?.rows <= 5) { + rows = 10 + } else { + rows = parseInt(req.query.rows) + } + + if (!req.query?.page) { + page = 0 + // eslint-disable-next-line eqeqeq + } else if (req.query.page <= 1) { + page = 0 + } else { + page = req.query.page + page = page * rows - rows + } + + const search = req.query?.search ? req.query.search : "" + + + const data = await InstalledDevice.find({ + userId: req.user_id, + $or: [ + { IMEI: { $regex: search, $options: 'i' } }, + ], + }).skip(page).limit(rows).sort({ created_at: -1 }).populate('deviceId') + + const total = Math.ceil((await InstalledDevice.countDocuments({ userId: req.user_id }))) + res.status(200).json({ data, total }) + +} + +module.exports.getAllForAdmin = async (req, res) => { + let page; + let rows; + if (!req.query?.rows || req.query?.rows <= 5) { + rows = 10 + } else { + rows = parseInt(req.query.rows) + } + + if (!req.query?.page) { + page = 0 + // eslint-disable-next-line eqeqeq + } else if (req.query.page <= 1) { + page = 0 + } else { + page = req.query.page + page = page * rows - rows + } + const search = req.query?.search ? req.query.search : "" + + const data = await InstalledDevice.find({ + $or: [ + { IMEI: { $regex: search, $options: 'i' } }, + ] + }).sort({ status: 1 }).skip(page).limit(rows) + .populate('deviceId') + .populate('userId', 'shopName shopNumber shopAddress birthDate score first_name last_name profilePic') + const total = Math.ceil((await InstalledDevice.estimatedDocumentCount())) + res.status(200).json({ data, total }) +} + + + +module.exports.updateInstalled = [ + [ + param('id').notEmpty().isMongoId().withMessage('لطفا ایدی را وارد یا تصحیح کنید'), + param('type').notEmpty().isString().withMessage('لطفا وضعیت را وارد یا تصحیح کنید'), + ], + checkValidations(validationResult), + async (req, res) => { + const installedDevice = await InstalledDevice.findById(req.params.id) + if (!installedDevice) { + throw res.status(404).json({ msg: 'این ایدی وجود ندارد' }) + } else { + const user = await User.findById(installedDevice.userId).select('walletBalance dollarBalance score') + const device = await Device.findById(installedDevice.deviceId) + switch (req.params.type) { + case "accept": { + + installedDevice.status = 1; + installedDevice.installationDate = new Date(); + + device.status = 1; + + user.walletBalance = device.profit + user.dollarBalance = device.dollarProfit + user.score = device.score + + + await Score.create({ + title:"ثبت دستگاه", + deviceId: device.id, + score: device.score, + userId: installedDevice.userId + }) + user.save() + device.save() + installedDevice.save() + res.status(201).json({ msg: _sr.fa.response.success_save, data: installedDevice }) + break; + } + case "reject": { + installedDevice.status = 2; + installedDevice.save() + device.status = 0; + device.save() + res.status(201).json({ msg: _sr.fa.response.success_save, data: installedDevice }) + break; + } + default: { + res.status(404).json({ msg: "استاتوس اشتباه است" }) + break; + } + } + } + } +] + diff --git a/server/controllers/GPS.Overview.js b/server/controllers/GPS.Overview.js new file mode 100644 index 0000000..225c675 --- /dev/null +++ b/server/controllers/GPS.Overview.js @@ -0,0 +1,23 @@ +const User = require('../models/User'); +const InstalledDevice = require('../models/GPS.InstalledDevice'); +const Withdraw = require('../models/GPS.Withdraw'); + + +module.exports.mainPage = async(req, res)=>{ + const device = await InstalledDevice.countDocuments({userId:req.user_id}) + const user = await User.findById(req.user_id).select('walletBalance dollarBalance score') + res.status(200).json({installedDevice:device, user}) +} + +module.exports.walletPage = async(req, res)=>{ + const withdraw = await Withdraw.findOne({userId: req.user_id, status:0}) + const user = await User.findById(req.user_id).select('walletBalance dollarBalance score') + let pending; + + if(withdraw){ + pending = true + }else{ + pending = false + } + res.status(200).json({user, pending }) +} \ No newline at end of file diff --git a/server/controllers/GPS.Request.js b/server/controllers/GPS.Request.js new file mode 100644 index 0000000..78ef4a6 --- /dev/null +++ b/server/controllers/GPS.Request.js @@ -0,0 +1,139 @@ +const { body, param, validationResult } = require('express-validator') +const { _sr } = require('../plugins/serverResponses') +const { checkValidations, res400 } = require('../plugins/controllersHelperFunctions') +const User = require('../models/User') +const RequestGPS = require('../models/GPS.Request') + +module.exports.gpsRequest = [ + [ + body('shopName').notEmpty().isString().withMessage(_sr.fa.required.name), + body('shopNumber').notEmpty().isString().withMessage(_sr.fa.required.store_number), + body('shopAddress').notEmpty().isString().withMessage(_sr.fa.required.address), + body('birthDate').notEmpty().isString().withMessage(_sr.fa.required.date), + ], + checkValidations(validationResult), + async (req, res) => { + const { shopName, shopNumber, shopAddress, birthDate, profilePic } = req.body; + const repeated = await RequestGPS.findOne({ userId: req.user_id }) + if (repeated) { + res400(res, "شما قبلا درخواست ثبت کرده اید") + } else { + const request = await RequestGPS.create({ + shopName, + shopNumber, + shopAddress, + birthDate, + profilePic, + userId: req.user_id, + }) + res.status(201).json({ msg: 'درخواست شما با موفقیت ثبت شد', date: request }) + } + + } +] + + +module.exports.getAllRequest = [ + async (req, res) => { + let page; + let rows; + if (!req.query?.rows) { + rows = 10 + } else { + rows = req.query.rows + } + if (!req.query?.page) { + page = 0 + // eslint-disable-next-line eqeqeq + } else if (!req.query.page == 1) { + page = 0 + } else { + page = req.query.page + page = page * rows - rows + } + const data = await RequestGPS.find({}).sort({ status: 1 }).skip(page).limit(rows) + .populate('userId', 'shopName shopNumber shopAddress birthDate score first_name last_name profilePic') + const total = Math.ceil((await RequestGPS.estimatedDocumentCount())) + res.status(200).json({ data, total }) + } +] + +module.exports.getOneRequest = [ + [ + param('id').notEmpty().isMongoId().withMessage('این ایدی اشتباه است') + ], + checkValidations(validationResult), + async (req, res) => { + const data = await RequestGPS.findById(req.params.id).populate('userId', 'shopName shopNumber shopAddress birthDate score first_name last_name profilePic') + res.status(200).json(data) + } +] + + +module.exports.changeStatus = [ + [ + param('status').notEmpty().isString().withMessage('این استاتوس اشتباه است'), + param('id').notEmpty().isMongoId().withMessage('این ایدی اشتباه است') + ], + checkValidations(validationResult), + async (req, res) => { + switch (req.params.status) { + case "accept": { + const data = await RequestGPS.findByIdAndUpdate(req.params.id, + { + status: 1 + }, + { new: true }) + const userPreData = await User.findById(data.userId).select('walletBalance dollarBalance score scope') + if(userPreData.scope.includes('gps')){ + const userData = await User.findByIdAndUpdate( + data.userId, + { + shopName: data.shopName, + shopNumber: data.shopNumber, + shopAddress: data.shopAddress, + birthDate: data.birthDate, + walletBalance: userPreData?.walletBalance | 0, + dollarBalance: userPreData?.dollarBalance | 0, + score: userPreData?.score | 0, + $push:{scope:'gps'} + }, + { new: true } + ).select('first_name last_name') + res.status(200).json({ msg: 'با موفقیت به روز شد', data: userData }) + + }else{ + const userData = await User.findByIdAndUpdate( + data.userId, + { + shopName: data.shopName, + shopNumber: data.shopNumber, + shopAddress: data.shopAddress, + birthDate: data.birthDate, + walletBalance: userPreData?.walletBalance | 0, + dollarBalance: userPreData?.dollarBalance | 0, + score: userPreData?.score | 0, + }, + { new: true } + ).select('first_name last_name') + res.status(200).json({ msg: 'با موفقیت به روز شد', data: userData }) + + } + break; + } + case "reject": { + const data = await RequestGPS.findByIdAndUpdate(req.params.id, + { + status: 2 + }, + { new: true }) + + res.status(200).json({ msg: 'با موفقیت به روز شد', data }) + break; + } + default: + res.status(400).json({ msg: 'این استاتوس اشتباه است' }) + break; + } + } +] diff --git a/server/controllers/GPS.Score.js b/server/controllers/GPS.Score.js new file mode 100644 index 0000000..ff9e2f5 --- /dev/null +++ b/server/controllers/GPS.Score.js @@ -0,0 +1,41 @@ +// const { body, param, validationResult } = require('express-validator') +// const { _sr } = require('../plugins/serverResponses') +// const { checkValidations } = require('../plugins/controllersHelperFunctions') +const Score = require('../models/GPS.Score') +const User = require('../models/User') + + + +module.exports.getAll = async (req, res) => { + let page; + let rows; + if (!req.query?.rows || req.query?.rows <= 5) { + rows = 10 + } else { + rows = parseInt(req.query.rows) + } + + if (!req.query?.page) { + page = 0 + // eslint-disable-next-line eqeqeq + } else if (req.query.page <= 1) { + page = 0 + } else { + page = req.query.page + page = page * rows - rows + } + const search = req.query?.search ? req.query.search : "" + + + const score = await Score.find({ + userId: req.user_id, + $or: [ + { title: { $regex: search, $options: 'i' } }, + { score: { $regex: search, $options: 'i' } }, + ], + }).skip(page).limit(rows); + const total = Math.ceil((await Score.countDocuments({ userId: req.user_id }))) + + const user = await User.findById(req.user_id).select('score') + res.status(200).json({ data: score, score: user.score, total }) +} diff --git a/server/controllers/GPS.Withdraw.js b/server/controllers/GPS.Withdraw.js new file mode 100644 index 0000000..5271ef5 --- /dev/null +++ b/server/controllers/GPS.Withdraw.js @@ -0,0 +1,134 @@ +const { body, param, validationResult } = require('express-validator'); +const { _sr } = require('../plugins/serverResponses'); +const { checkValidations } = require('../plugins/controllersHelperFunctions'); +const User = require('../models/User'); +const Withdraw = require('../models/GPS.Withdraw'); + + +module.exports.createRequest = [ + [ + body('card').notEmpty().isObject().withMessage('گارت ورودی خود را انتخاب کنید'), + ], + checkValidations(validationResult), + async (req, res) => { + try { + const withdraw = await Withdraw.findOne({userId: req.user_id, status:0}) + if(withdraw){ + res.status(400).json({ msg: 'شما درخواست درحال بررسی دارید' }) + }else{ + const user = await User.findById(req.user_id) + const data = { + card: req.body.card, + userId: req.user_id, + amount: user.walletBalance, + dollarAmount: user.dollarBalance, + status: 0 + } + + const request = await Withdraw.create(data) + user.dollarBalance = 0; + user.walletBalance = 0; + user.save() + res.status(201).json({ msg: _sr.fa.response.success_save, data: request }) + } + + } catch (error) { + res.status(500).json({ msg: error }) + + } + } +] + + +module.exports.getAllForUser = async (req, res) => { + let page; + let rows; + if (!req.query?.rows || req.query?.rows <= 5) { + rows = 10 + } else { + rows = parseInt(req.query.rows) + } + + if (!req.query?.page) { + page = 0 + // eslint-disable-next-line eqeqeq + } else if (req.query.page <= 1) { + page = 0 + } else { + page = req.query.page + page = page * rows - rows + } + const search = req.query?.search ? req.query.search : "" + + + const data = await Withdraw.find({ + userId: req.user_id, + $or: [ + { amount: { $regex: search, $options: 'i' } }, + { dollarAmount: { $regex: search, $options: 'i' } }, + { trackingNumber: { $regex: search, $options: 'i' } }, + ], + }).skip(page).limit(rows).sort({ created_at: -1 }); + const total = Math.ceil((await Withdraw.countDocuments({ userId: req.user_id }))) + res.status(201).json({ data, total }) +} + +module.exports.getAllForAdmin = async (req, res) => { + let page; + let rows; + if (!req.query?.rows || req.query?.rows <= 5) { + rows = 10 + } else { + rows = parseInt(req.query.rows) + } + + if (!req.query?.page) { + page = 0 + // eslint-disable-next-line eqeqeq + } else if (req.query.page <= 1) { + page = 0 + } else { + page = req.query.page + page = page * rows - rows + } + const data = await Withdraw.find().sort({ status: 1 }).skip(page).limit(rows) + .populate('userId', 'shopName shopNumber shopAddress birthDate score first_name last_name profilePic') + const total = Math.ceil((await Withdraw.estimatedDocumentCount())) + res.status(201).json({ data, total }) +} + + +module.exports.updateReq = [ + [ + param('id').notEmpty().isMongoId().withMessage('ایدی را باید وارد کنید'), + param('type').notEmpty().isString().withMessage('وضعیت را باید وارد کنید'), + ], + checkValidations(validationResult), + async (req, res) => { + const request = await Withdraw.findById(req.params.id) + if (!request) { + res.status(404).json({ msg: _sr.fa.not_found.item_id }) + } else { + switch (req.params.type) { + case "accept": { + request.status = 1; + request.save() + res.status(201).json({ msg: _sr.fa.response.success_save, data: request }) + break; + } + case "deposit": { + request.status = 2; + request.depositDate = new Date(); + request.trackingNumber = req.body.trackingNumber || 0; + request.save() + res.status(201).json({ msg: _sr.fa.response.success_save, data: request }) + break; + } + default: { + res.status(404).json({ msg: "استاتوس اشتباه است" }) + break; + } + } + } + } +] \ No newline at end of file diff --git a/server/controllers/userController.js b/server/controllers/userController.js index 49c8d9d..1cb7ac9 100644 --- a/server/controllers/userController.js +++ b/server/controllers/userController.js @@ -24,7 +24,18 @@ const { generateRandomDigits } = require('../plugins/controllersHelperFunctions') const _faSr = _sr.fa - +const transporter = nodemailer.createTransport({ + host: 'smtp.c1.liara.email', + port: 587, + secure: false, // true for 465, false for other ports + auth: { + user: 'awesome_bell_ncc1hi', + pass: '509f8938-db95-4b8d-83e7-9ea8eccfd28b' + }, + tls: { + rejectUnauthorized: false + } +}) /// ///////////////////////////////////////////////////////////////// verify account functions function sendConfirmationEmail(userId) { return new Promise(async (resolve, reject) => { @@ -38,18 +49,7 @@ function sendConfirmationEmail(userId) { /// //// email configs // const hostURL = 'www.asan-service.com' - const transporter = nodemailer.createTransport({ - host: 'smtp.c1.liara.email', - port: 587, - secure: false, // true for 465, false for other ports - auth: { - user: 'awesome_bell_ncc1hi', - pass: '509f8938-db95-4b8d-83e7-9ea8eccfd28b' - }, - tls: { - rejectUnauthorized: false - } - }) + const emailHTMLTemplate = `