chore: add otp based login
This commit is contained in:
@@ -13,7 +13,7 @@ jobs:
|
|||||||
DANAK_SERVER: "https://captain.run.danakcorp.com"
|
DANAK_SERVER: "https://captain.run.danakcorp.com"
|
||||||
APP_TOKEN: 5a2526d13383aa8c4c3e6019352b96cf81e84b7b781e80c2b8012eaf5e2e69fd
|
APP_TOKEN: 5a2526d13383aa8c4c3e6019352b96cf81e84b7b781e80c2b8012eaf5e2e69fd
|
||||||
CAPROVER_APP_NAME: ostandari
|
CAPROVER_APP_NAME: ostandari
|
||||||
GITHUB_TOKEN: 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
|
GITHUB_TOKEN: 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
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Check out repositorys
|
- name: Check out repositorys
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# Use the official Node.js image as a base
|
||||||
|
FROM node:20-alpine
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY package*.json ./
|
||||||
|
|
||||||
|
RUN npm install
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
RUN mkdir -p /app/.nuxt && chown -R node:node /app
|
||||||
|
|
||||||
|
USER node
|
||||||
|
|
||||||
|
EXPOSE 3000
|
||||||
|
|
||||||
|
CMD ["npm", "run", "dev"]
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
services:
|
||||||
|
app:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile.dev
|
||||||
|
container_name: ostandari-dev
|
||||||
|
# working_dir: /app
|
||||||
|
volumes:
|
||||||
|
- .:/app
|
||||||
|
- /app/node_modules
|
||||||
|
ports:
|
||||||
|
- "3000:3000"
|
||||||
|
command: ["npm", "run", "dev"]
|
||||||
|
environment:
|
||||||
|
NODE_ENV: development
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
mongo_data:
|
||||||
Generated
+41
-3
@@ -29,6 +29,7 @@
|
|||||||
"element-ui": "^2.15.1",
|
"element-ui": "^2.15.1",
|
||||||
"express": "^4.17.1",
|
"express": "^4.17.1",
|
||||||
"express-fileupload": "^1.2.1",
|
"express-fileupload": "^1.2.1",
|
||||||
|
"express-rate-limit": "^7.4.1",
|
||||||
"express-validator": "^6.10.1",
|
"express-validator": "^6.10.1",
|
||||||
"gsap": "^3.6.1",
|
"gsap": "^3.6.1",
|
||||||
"jquery": "^3.7.1",
|
"jquery": "^3.7.1",
|
||||||
@@ -39,6 +40,7 @@
|
|||||||
"mongoose": "^5.12.5",
|
"mongoose": "^5.12.5",
|
||||||
"mongoose-paginate-v2": "^1.3.18",
|
"mongoose-paginate-v2": "^1.3.18",
|
||||||
"morgan": "^1.10.0",
|
"morgan": "^1.10.0",
|
||||||
|
"node-cache": "^5.1.2",
|
||||||
"nodemailer": "^6.6.0",
|
"nodemailer": "^6.6.0",
|
||||||
"nodemon": "^3.1.2",
|
"nodemon": "^3.1.2",
|
||||||
"nuxt": "^2.15.3",
|
"nuxt": "^2.15.3",
|
||||||
@@ -7333,6 +7335,15 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/clone": {
|
||||||
|
"version": "2.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
|
||||||
|
"integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/code-point-at": {
|
"node_modules/code-point-at": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
|
||||||
@@ -8840,9 +8851,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/elliptic": {
|
"node_modules/elliptic": {
|
||||||
"version": "6.5.7",
|
"version": "6.6.1",
|
||||||
"resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.7.tgz",
|
"resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz",
|
||||||
"integrity": "sha512-ESVCtTwiA+XhY3wyh24QqRGBoP3rEdDUl3EDUUo9tft074fi19IrdpH7hLCMMP3CIj7jb3W96rn8lt/BqIlt5Q==",
|
"integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bn.js": "^4.11.9",
|
"bn.js": "^4.11.9",
|
||||||
@@ -9379,6 +9390,21 @@
|
|||||||
"node": ">=12.0.0"
|
"node": ">=12.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/express-rate-limit": {
|
||||||
|
"version": "7.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.4.1.tgz",
|
||||||
|
"integrity": "sha512-KS3efpnpIDVIXopMc65EMbWbUht7qvTCdtCR2dD/IZmi9MIkopYESwyRqLgv8Pfu589+KqDqOdzJWW7AHoACeg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 16"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/express-rate-limit"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"express": "4 || 5 || ^5.0.0-beta.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/express-validator": {
|
"node_modules/express-validator": {
|
||||||
"version": "6.15.0",
|
"version": "6.15.0",
|
||||||
"resolved": "https://registry.npmjs.org/express-validator/-/express-validator-6.15.0.tgz",
|
"resolved": "https://registry.npmjs.org/express-validator/-/express-validator-6.15.0.tgz",
|
||||||
@@ -13547,6 +13573,18 @@
|
|||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/node-cache": {
|
||||||
|
"version": "5.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-cache/-/node-cache-5.1.2.tgz",
|
||||||
|
"integrity": "sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"clone": "2.x"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 8.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/node-fetch": {
|
"node_modules/node-fetch": {
|
||||||
"version": "2.7.0",
|
"version": "2.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
|
||||||
|
|||||||
@@ -32,6 +32,7 @@
|
|||||||
"element-ui": "^2.15.1",
|
"element-ui": "^2.15.1",
|
||||||
"express": "^4.17.1",
|
"express": "^4.17.1",
|
||||||
"express-fileupload": "^1.2.1",
|
"express-fileupload": "^1.2.1",
|
||||||
|
"express-rate-limit": "^7.4.1",
|
||||||
"express-validator": "^6.10.1",
|
"express-validator": "^6.10.1",
|
||||||
"gsap": "^3.6.1",
|
"gsap": "^3.6.1",
|
||||||
"jquery": "^3.7.1",
|
"jquery": "^3.7.1",
|
||||||
@@ -42,6 +43,7 @@
|
|||||||
"mongoose": "^5.12.5",
|
"mongoose": "^5.12.5",
|
||||||
"mongoose-paginate-v2": "^1.3.18",
|
"mongoose-paginate-v2": "^1.3.18",
|
||||||
"morgan": "^1.10.0",
|
"morgan": "^1.10.0",
|
||||||
|
"node-cache": "^5.1.2",
|
||||||
"nodemailer": "^6.6.0",
|
"nodemailer": "^6.6.0",
|
||||||
"nodemon": "^3.1.2",
|
"nodemon": "^3.1.2",
|
||||||
"nuxt": "^2.15.3",
|
"nuxt": "^2.15.3",
|
||||||
|
|||||||
@@ -0,0 +1,81 @@
|
|||||||
|
const { validationResult, query } = require("express-validator");
|
||||||
|
const Logger = require("../models/Logger");
|
||||||
|
const { paginationOptions } = require("../plugins/pagination");
|
||||||
|
|
||||||
|
// get admin login logs with optional filtering and pagination
|
||||||
|
module.exports.getAdminLoginLogs = [
|
||||||
|
[
|
||||||
|
query("page")
|
||||||
|
.optional()
|
||||||
|
.isInt({ min: 1 })
|
||||||
|
.withMessage("Page must be a positive integer."),
|
||||||
|
query("limit")
|
||||||
|
.optional()
|
||||||
|
.isInt({ min: 1 })
|
||||||
|
.withMessage("Limit must be a positive integer."),
|
||||||
|
query("sort")
|
||||||
|
.optional()
|
||||||
|
.isIn(["asc", "desc"])
|
||||||
|
.withMessage('Sort must be either "asc" or "desc".'),
|
||||||
|
query("fromDate")
|
||||||
|
.optional()
|
||||||
|
.isISO8601()
|
||||||
|
.withMessage("From date must be a valid date."),
|
||||||
|
query("toDate")
|
||||||
|
.optional()
|
||||||
|
.isISO8601()
|
||||||
|
.withMessage("To date must be a valid date."),
|
||||||
|
],
|
||||||
|
async (req, res) => {
|
||||||
|
const errors = validationResult(req);
|
||||||
|
if (!errors.isEmpty())
|
||||||
|
return res.status(422).json({ validation: errors.mapped() });
|
||||||
|
|
||||||
|
try {
|
||||||
|
const {
|
||||||
|
page = 1,
|
||||||
|
limit = 1000,
|
||||||
|
sort = "desc",
|
||||||
|
fromDate,
|
||||||
|
toDate,
|
||||||
|
} = req?.query;
|
||||||
|
|
||||||
|
const filters = {};
|
||||||
|
if (fromDate) filters.LastLogin = { $gte: new Date(fromDate) };
|
||||||
|
if (toDate)
|
||||||
|
filters.LastLogin = { ...filters.LastLogin, $lte: new Date(toDate) };
|
||||||
|
|
||||||
|
const options = paginationOptions({ page, limit, sort });
|
||||||
|
const logs = await Logger.find(filters)
|
||||||
|
.populate({ path: "user", select: { password: 0 } })
|
||||||
|
.sort({ updated_at: sort === "desc" ? -1 : 1 })
|
||||||
|
.skip(options.skip)
|
||||||
|
.limit(options.limit);
|
||||||
|
|
||||||
|
const totalLogs = await Logger.countDocuments(filters);
|
||||||
|
const totalPages = Math.ceil(totalLogs / options.limit);
|
||||||
|
|
||||||
|
return res.status(200).json({
|
||||||
|
logs: logs.map((log) => {
|
||||||
|
log.LastLogin = new Date(log.LastLogin).toLocaleString("fa-IR", {
|
||||||
|
timeZone: "Asia/Tehran",
|
||||||
|
// hour: "2-digit",
|
||||||
|
// minute: "2-digit",
|
||||||
|
// day: "2-digit",
|
||||||
|
// month: "2-digit",
|
||||||
|
// weekday: "short",
|
||||||
|
// year: "2-digit",
|
||||||
|
// timeZoneName: "long",
|
||||||
|
});
|
||||||
|
return log;
|
||||||
|
}),
|
||||||
|
page: options.page,
|
||||||
|
totalPages,
|
||||||
|
totalLogs,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching admin login logs:", error);
|
||||||
|
return res.status(500).json({ message: "Server error occurred." });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
];
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
const User = require("../models/User");
|
const User = require("../models/User");
|
||||||
const { body, validationResult } = require("express-validator");
|
const { body, validationResult } = require("express-validator");
|
||||||
|
const { rateLimit } = require("express-rate-limit");
|
||||||
const bcrypt = require("bcryptjs");
|
const bcrypt = require("bcryptjs");
|
||||||
const jwt = require("jsonwebtoken");
|
const jwt = require("jsonwebtoken");
|
||||||
const crypto = require("crypto");
|
const crypto = require("crypto");
|
||||||
@@ -17,6 +18,9 @@ const fs = require("fs");
|
|||||||
const nodemailer = require("nodemailer");
|
const nodemailer = require("nodemailer");
|
||||||
const Category = require("../models/Category");
|
const Category = require("../models/Category");
|
||||||
const Logger = require("../models/Logger");
|
const Logger = require("../models/Logger");
|
||||||
|
const cacheService = require("../plugins/cache");
|
||||||
|
const { sms } = require("../plugins/sms");
|
||||||
|
|
||||||
////// variables
|
////// variables
|
||||||
const profileWidth = 500;
|
const profileWidth = 500;
|
||||||
const profileHeight = 500;
|
const profileHeight = 500;
|
||||||
@@ -25,11 +29,19 @@ const hostURL = "localhost:6688";
|
|||||||
const limit = 20;
|
const limit = 20;
|
||||||
const select = "-password -token";
|
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 */
|
/** @todo add private to query */
|
||||||
|
|
||||||
/** auth --------------------------------------------- */
|
/** auth --------------------------------------------- */
|
||||||
/////////////////////////////////////////////////////////////////////// login
|
/////////////////////////////////////////////////////////////////////// login
|
||||||
module.exports.login = [
|
module.exports.login = [
|
||||||
|
limiter,
|
||||||
[
|
[
|
||||||
body("username")
|
body("username")
|
||||||
.if((value, { req }) => {
|
.if((value, { req }) => {
|
||||||
@@ -138,6 +150,170 @@ module.exports.login = [
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
/** 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) => {
|
||||||
|
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);
|
||||||
|
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() } },
|
||||||
|
{ 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
|
/////////////////////////////////////////////////////////////////////// logout
|
||||||
module.exports.logout = [
|
module.exports.logout = [
|
||||||
|
|||||||
@@ -6,7 +6,8 @@
|
|||||||
|
|
||||||
// const databaseURL = 'mongodb://ostanmri_user:admin1234@localhost:27017/ostanmri_database'
|
// const databaseURL = 'mongodb://ostanmri_user:admin1234@localhost:27017/ostanmri_database'
|
||||||
const databaseURL =
|
const databaseURL =
|
||||||
"mongodb://root:f2d63313cc3ed6ff@srv-captain--ostandari-db:27017/ostan_db?authSource=admin";
|
// "mongodb://root:f2d63313cc3ed6ff@srv-captain--ostandari-db:27017/ostan_db?authSource=admin";
|
||||||
|
"mongodb://root:f2d63313cc3ed6ff@danak-db-public.danakcorp.com:50123/ostan_db?authSource=admin";
|
||||||
//const databaseURL = 'mongodb://danakcorp:danakcorp%212024@ostan-mr.ir:27017/ostan_db?serverSelectionTimeoutMS=5000&connectTimeoutMS=10000&authSource=admin&authMechanism=SCRAM-SHA-1'
|
//const databaseURL = 'mongodb://danakcorp:danakcorp%212024@ostan-mr.ir:27017/ostan_db?serverSelectionTimeoutMS=5000&connectTimeoutMS=10000&authSource=admin&authMechanism=SCRAM-SHA-1'
|
||||||
|
|
||||||
// const databaseURL = 'mongodb://ostanmri_user:admin1234@91.98.96.174:27017/ostanmri_database?serverSelectionTimeoutMS=5000&connectTimeoutMS=10000&authSource=ostanmri_database'
|
// const databaseURL = 'mongodb://ostanmri_user:admin1234@91.98.96.174:27017/ostanmri_database?serverSelectionTimeoutMS=5000&connectTimeoutMS=10000&authSource=ostanmri_database'
|
||||||
|
|||||||
+4
-7
@@ -8,7 +8,7 @@ const {
|
|||||||
isLoggedIn,
|
isLoggedIn,
|
||||||
hasPermission,
|
hasPermission,
|
||||||
} = require("./authentication");
|
} = require("./authentication");
|
||||||
const bodyParser = require("body-parser");
|
// const bodyParser = require("body-parser");
|
||||||
const cronJobs = require("./plugins/cronJobs");
|
const cronJobs = require("./plugins/cronJobs");
|
||||||
const swaggerJsdoc = require("swagger-jsdoc");
|
const swaggerJsdoc = require("swagger-jsdoc");
|
||||||
const cors = require("cors");
|
const cors = require("cors");
|
||||||
@@ -66,10 +66,11 @@ const options = {
|
|||||||
apis: ["./server/routes/*.js"],
|
apis: ["./server/routes/*.js"],
|
||||||
};
|
};
|
||||||
|
|
||||||
// const specs = swaggerJsdoc(options);
|
const specs = swaggerJsdoc(options);
|
||||||
|
|
||||||
cronJobs();
|
cronJobs();
|
||||||
createAdmins();
|
createAdmins();
|
||||||
|
|
||||||
const corsOptions = {
|
const corsOptions = {
|
||||||
origin: "*",
|
origin: "*",
|
||||||
credentials: true,
|
credentials: true,
|
||||||
@@ -81,11 +82,7 @@ app.use(express.json());
|
|||||||
app.use(express.urlencoded({ extended: true }));
|
app.use(express.urlencoded({ extended: true }));
|
||||||
app.use(fileUpload());
|
app.use(fileUpload());
|
||||||
app.use(cors(corsOptions));
|
app.use(cors(corsOptions));
|
||||||
// app.use(
|
app.use("/v1", swaggerUi.serve, swaggerUi.setup(specs, { explorer: true }));
|
||||||
// "/v1",
|
|
||||||
// swaggerUi.serve,
|
|
||||||
// swaggerUi.setup(specs , {explorer:true})
|
|
||||||
// );
|
|
||||||
// Require & Import API routes
|
// Require & Import API routes
|
||||||
const Public = require("./routes/public");
|
const Public = require("./routes/public");
|
||||||
const admin = require("./routes/admin");
|
const admin = require("./routes/admin");
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
const mongoose = require('mongoose');
|
const mongoose = require("mongoose");
|
||||||
const mongoosePaginate = require('mongoose-paginate-v2');
|
const mongoosePaginate = require("mongoose-paginate-v2");
|
||||||
|
|
||||||
const LoggerSchema = mongoose.Schema({
|
const LoggerSchema = mongoose.Schema({
|
||||||
LastLogin: String,
|
LastLogin: String,
|
||||||
user :{type: mongoose.Schema.Types.ObjectId, ref: 'User'},
|
user: { type: mongoose.Schema.Types.ObjectId, ref: "User" },
|
||||||
});
|
});
|
||||||
|
|
||||||
LoggerSchema.plugin(mongoosePaginate);
|
LoggerSchema.plugin(mongoosePaginate);
|
||||||
|
|
||||||
module.exports = mongoose.model('Logger', LoggerSchema);
|
module.exports = mongoose.model("Logger", LoggerSchema);
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
const NodeCache = require("node-cache");
|
||||||
|
|
||||||
|
class CacheService extends NodeCache {}
|
||||||
|
module.exports = new CacheService();
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
exports.paginationOptions = ({ page, limit, sort }) => {
|
||||||
|
const parsedPage = parseInt(page, 10) || 1;
|
||||||
|
const parsedLimit = parseInt(limit, 10) || 10;
|
||||||
|
const parsedSort = sort === "asc" ? "asc" : "desc";
|
||||||
|
|
||||||
|
return {
|
||||||
|
page: parsedPage,
|
||||||
|
limit: parsedLimit,
|
||||||
|
sort: parsedSort,
|
||||||
|
skip: (parsedPage - 1) * parsedLimit,
|
||||||
|
};
|
||||||
|
};
|
||||||
+546
-533
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,47 @@
|
|||||||
|
const axios = require("axios");
|
||||||
|
module.exports.sms = async (phoneNumber, message) => {
|
||||||
|
try {
|
||||||
|
// get token
|
||||||
|
const getToken = await axios.post("https://RestfulSms.com/api/Token", {
|
||||||
|
UserApiKey: "569ee43ed0d9ac27708ce43d",
|
||||||
|
SecretKey: "drtime@A!@#",
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!getToken.data.IsSuccessful) {
|
||||||
|
throw new Error("sending sms failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
const token = getToken.data.TokenKey;
|
||||||
|
//get lines
|
||||||
|
const resData = await axios.get("https://RestfulSms.com/api/SMSLine", {
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"x-sms-ir-secure-token": token,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// message details
|
||||||
|
const data = {
|
||||||
|
Messages: [message],
|
||||||
|
MobileNumbers: [phoneNumber],
|
||||||
|
LineNumber: resData.data.SMSLines[0].LineNumber,
|
||||||
|
SendDateTime: "",
|
||||||
|
CanContinueInCaseOfError: "false",
|
||||||
|
};
|
||||||
|
|
||||||
|
const response = await axios.post(
|
||||||
|
`http://RestfulSms.com/api/MessageSend`,
|
||||||
|
data,
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"x-sms-ir-secure-token": token,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return response.data;
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
};
|
||||||
+220
-151
File diff suppressed because it is too large
Load Diff
+89
-12
@@ -1,7 +1,7 @@
|
|||||||
const {Router} = require('express')
|
const { Router } = require("express");
|
||||||
const router = Router()
|
const router = Router();
|
||||||
const userController = require('../controllers/userController');
|
const userController = require("../controllers/userController");
|
||||||
const electionController = require('../controllers/electionController');
|
const electionController = require("../controllers/electionController");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @swagger
|
* @swagger
|
||||||
@@ -48,7 +48,84 @@ const electionController = require('../controllers/electionController');
|
|||||||
* description: Validation error. Indicates that the request body contains invalid data.
|
* description: Validation error. Indicates that the request body contains invalid data.
|
||||||
*/
|
*/
|
||||||
// Login User
|
// Login User
|
||||||
router.post('/login', userController.login);
|
router.post("/login", userController.login);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @swagger
|
||||||
|
* /auth/otp:
|
||||||
|
* post:
|
||||||
|
* summary: Send OTP to user for login
|
||||||
|
* description: Allows users to log in with their phone number by sending an OTP.
|
||||||
|
* tags:
|
||||||
|
* - Auth
|
||||||
|
* requestBody:
|
||||||
|
* required: true
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* type: object
|
||||||
|
* properties:
|
||||||
|
* phone:
|
||||||
|
* type: string
|
||||||
|
* example:
|
||||||
|
* phone: "09124569875"
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: OTP sent successfully.
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* type: object
|
||||||
|
* properties:
|
||||||
|
* message:
|
||||||
|
* type: string
|
||||||
|
* example:
|
||||||
|
* message: "OTP sent successfully."
|
||||||
|
*/
|
||||||
|
router.post("/otp", userController.otp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @swagger
|
||||||
|
* /auth/otp/verify:
|
||||||
|
* post:
|
||||||
|
* summary: Verify the OTP sent to user
|
||||||
|
* description: Allows users to log in by verifying the OTP sent to their phone number.
|
||||||
|
* tags:
|
||||||
|
* - Auth
|
||||||
|
* requestBody:
|
||||||
|
* required: true
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* type: object
|
||||||
|
* properties:
|
||||||
|
* phone:
|
||||||
|
* type: string
|
||||||
|
* code:
|
||||||
|
* type: string
|
||||||
|
* example:
|
||||||
|
* phone: "09124569875"
|
||||||
|
* code: "12345"
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: User logged in successfully.
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* type: object
|
||||||
|
* properties:
|
||||||
|
* token:
|
||||||
|
* type: string
|
||||||
|
* example:
|
||||||
|
* token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
||||||
|
* 401:
|
||||||
|
* description: Unauthorized. Indicates that the provided credentials are invalid.
|
||||||
|
* 403:
|
||||||
|
* description: Forbidden. Indicates that the account is inactive. Contact the admin for assistance.
|
||||||
|
* 422:
|
||||||
|
* description: Validation error. Indicates that the request body contains invalid data.
|
||||||
|
*/
|
||||||
|
router.post("/otp/verify", userController.verifyOtp);
|
||||||
/**
|
/**
|
||||||
* @swagger
|
* @swagger
|
||||||
* /auth/logout:
|
* /auth/logout:
|
||||||
@@ -73,7 +150,7 @@ router.post('/login', userController.login);
|
|||||||
* description: Unauthorized. Indicates that the user is not logged in.
|
* description: Unauthorized. Indicates that the user is not logged in.
|
||||||
*/
|
*/
|
||||||
// Logout User
|
// Logout User
|
||||||
router.delete('/logout', userController.logout);
|
router.delete("/logout", userController.logout);
|
||||||
/**
|
/**
|
||||||
* @swagger
|
* @swagger
|
||||||
* /auth/user:
|
* /auth/user:
|
||||||
@@ -96,7 +173,7 @@ router.delete('/logout', userController.logout);
|
|||||||
* description: Unauthorized. Indicates that the user is not authenticated or the token is invalid.
|
* description: Unauthorized. Indicates that the user is not authenticated or the token is invalid.
|
||||||
*/
|
*/
|
||||||
// Data User
|
// Data User
|
||||||
router.get('/user', userController.getuser);
|
router.get("/user", userController.getuser);
|
||||||
/**
|
/**
|
||||||
* @swagger
|
* @swagger
|
||||||
* /auth/forget-password:
|
* /auth/forget-password:
|
||||||
@@ -154,7 +231,7 @@ router.get('/user', userController.getuser);
|
|||||||
* description: Error message indicating the internal server error.
|
* description: Error message indicating the internal server error.
|
||||||
*/
|
*/
|
||||||
// Change Password
|
// Change Password
|
||||||
router.post('/changePassword' , userController.forgetPassGenerateToken);
|
router.post("/changePassword", userController.forgetPassGenerateToken);
|
||||||
/**
|
/**
|
||||||
* @swagger
|
* @swagger
|
||||||
* /auth/changePassword/{token}:
|
* /auth/changePassword/{token}:
|
||||||
@@ -213,7 +290,7 @@ router.post('/changePassword' , userController.forgetPassGenerateToken);
|
|||||||
* description: Error message indicating the internal server error.
|
* description: Error message indicating the internal server error.
|
||||||
*/
|
*/
|
||||||
// Change Password :token param
|
// Change Password :token param
|
||||||
router.put('/changePassword/:token' , userController.forgetPassGetToken);
|
router.put("/changePassword/:token", userController.forgetPassGetToken);
|
||||||
|
|
||||||
///////// voter
|
///////// voter
|
||||||
|
|
||||||
@@ -272,7 +349,7 @@ router.put('/changePassword/:token' , userController.forgetPassGetToken);
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
//Voter Login
|
//Voter Login
|
||||||
router.post('/voter/login' , electionController.voterLogin);
|
router.post("/voter/login", electionController.voterLogin);
|
||||||
/**
|
/**
|
||||||
* @swagger
|
* @swagger
|
||||||
* /auth/voter/user:
|
* /auth/voter/user:
|
||||||
@@ -316,6 +393,6 @@ router.post('/voter/login' , electionController.voterLogin);
|
|||||||
* description: Error message indicating the internal server error.
|
* description: Error message indicating the internal server error.
|
||||||
*/
|
*/
|
||||||
// user Voter Data
|
// user Voter Data
|
||||||
router.get('/voter/user' , electionController.getVoterUser);
|
router.get("/voter/user", electionController.getVoterUser);
|
||||||
|
|
||||||
module.exports = router
|
module.exports = router;
|
||||||
|
|||||||
Reference in New Issue
Block a user