diff --git a/app/controllers/establishment.controller.js b/app/controllers/establishment.controller.js index 0972b6e..46c7ba4 100644 --- a/app/controllers/establishment.controller.js +++ b/app/controllers/establishment.controller.js @@ -7,6 +7,7 @@ const EstablishmentProduct = db.EstablishmentProduct; const CityTown = db.CityTown; const Emirate = db.Emirate; const user = db.user; +const User = db.user; const Product = db.Product; const ExcelJS = require("exceljs"); const { Op, Sequelize } = require("sequelize"); @@ -1049,6 +1050,81 @@ exports.forgotPasswordVerifyOTP = async (req, res) => { } }; +exports.requestOTPForLogin = async (req, res) => { + try { + const { registered_email } = req.body; + + if (!registered_email) { + return res.status(400).json({ + status: "failed", + message: "Email is required", + }); + } + + // Check which model contains the user + let loggingUser = await EstablishmentUser.findOne({ + where: { email: registered_email } + }); + let userModel = EstablishmentUser; + + if (!loggingUser) { + loggingUser = await User.findOne({ + where: { email: registered_email, is_active: true } + }); + userModel = User; + } + + if (!loggingUser) { + logger.warn(`OTP requested for non-existing email: ${sanitizeForLog(registered_email)}`); + return res.status(404).json({ + status: "failed", + message: "Invalid login request. Please check your email or register to continue.", + }); + } + + // Secure OTP generation + const otp = crypto.randomInt(100000, 999999).toString(); + + // Hash OTP before storing + const hashedOtp = await bcrypt.hash(otp, 10); + + // Store OTP in the correct model with WHERE clause + await userModel.update( + { + login_otp: hashedOtp, + login_otp_expires_at: new Date(Date.now() + 10 * 60 * 1000), + }, + { + where: { email: registered_email } + } + ); + const placeHolderData = { + username: loggingUser.name, + verfication_code: otp, + support_email: process.env.SUPPORT_EMAIL, + support_phone: process.env.SUPPORT_PHONE + }; + + await sendEmailService(registered_email, "sign_in_verification_code", placeHolderData); + + logger.info(`Login OTP email triggered for: ${sanitizeForLog(registered_email)}`); + + return res.status(200).json({ + status: "success", + message: "OTP sent successfully to your registered email", + }); + + } catch (err) { + logger.error(`OTP request failed: ${err.message}`); + logger.error(err.stack); + + return res.status(500).json({ + status: "failed", + message: "Internal Server Error", + }); + } +}; + const GENERIC_ERROR_MSG = "Invalid data. Please check the instructions given and upload again."; diff --git a/app/routes/routes.js b/app/routes/routes.js index fbb79ff..3e92d26 100644 --- a/app/routes/routes.js +++ b/app/routes/routes.js @@ -17,7 +17,6 @@ const ConfigController = require("../controllers/config.controller"); const dashboardController = require("../controllers/dashboard.controller"); const notificationTemplateController = require("../controllers/notificationTemplate.controller"); const quarterlyWindowsController = require("../controllers/quarterlyWindowsConfiguration.controller"); -const calculationController = require("../controllers/calculation.controller"); const ManufacturingIpiController = require("../controllers/manufacturingIPI.controller") const fs = require("fs"); const path = require("path"); @@ -26,115 +25,7 @@ const { UPLOAD_DIR } = require("../config/upload.config"); const upload = multer({ dest: UPLOAD_DIR }); - - -/** - * @swagger - * /api/calculate_base_year: - * post: - * summary: Base year calculation 2022 - * tags: [IIP Calculation] - * security: - * - appSignature: [] - * - CSRF: [] - * requestBody: - * required: true - * content: - * application/json: - * schema: - * type: object - * required: - * - baseYear - * - forceRecalculate - * properties: - * baseYear: - * type: integer - * example: 2022 - * forceRecalculate: - * type: string - * example: false - * responses: - * 200: - * description: Base year production calculated successfully - */ - -router.post("/calculate_base_year",[] , calculationController.calculate_base_year); - -/** - * @swagger - * /api/survey_auto_submit: - * post: - * summary: Auto survey submission for Quarter - * tags: [IIP Calculation] - * security: - * - appSignature: [] - * - CSRF: [] - * requestBody: - * required: true - * content: - * application/json: - * schema: - * type: object - * required: - * - year - * - quarter - * properties: - * year: - * type: integer - * example: 2025 - * quarter: - * type: string - * enum: [Q1, Q2, Q3, Q4] - * example: Q2 - * responses: - * 200: - * description: Auto survey completed successfully - */ -router.post("/survey_auto_submit",[] , calculationController.survey_auto_submit); - -/** - * @swagger - * /api/calculate_quarter: - * post: - * summary: Calculate IPI for a selected year and quarter (Quarter → Month mapping) - * tags: [IIP Calculation] - * security: - * - appSignature: [] - * - CSRF: [] - * requestBody: - * required: true - * content: - * application/json: - * schema: - * type: object - * required: - * - year - * - quarter - * properties: - * year: - * type: integer - * example: 2025 - * quarter: - * type: string - * enum: [Q1, Q2, Q3, Q4] - * example: Q2 - * description: | - * Quarter to month mapping: - * - Q1 → Jan to Mar (1 - 3) - * - Q2 → Apr to Jun (4 - 6) - * - Q3 → Jul to Sep (7 - 9) - * - Q4 → Oct to Dec (10 - 12) - * responses: - * 200: - * description: Quarterly IPI calculation completed successfully - */ - -router.post("/calculate_quarter",[] , calculationController.calculate_quarter); - - -router.get("/calculate_month",[] , calculationController.calculate_month); - - + /** * @swagger @@ -3158,6 +3049,35 @@ router.get("/manufacturing/getManufacturingIndex",[verifySignature, verifyToken] router.get("/manufacturing/getManufacturingMonthlyOverview", [verifySignature, verifyToken], ManufacturingIpiController.getManufacturingMonthlyOverviewByYearMonth); +/** + * @swagger + * /api/login/request-otp: + * post: + * summary: Request OTP for login Admin or Establishment User + * tags: [Admin And Establishments User Auth] + * security: + * - appSignature: [] + * requestBody: + * required: true + * content: + * application/json: + * schema: + * type: object + * required: + * - registered_email + * properties: + * registered_email: { type: string, example: "contact@abcindustries.com" } + * responses: + * 200: + * description: OTP sent successfully + * 400: + * description: Missing or invalid data + * 404: + * description: Establishment or user not found + * 500: + * description: Server error + */ +router.post("/login/request-otp",[verifySignature], establishmentController.requestOTPForLogin); diff --git a/server.js b/server.js index 7e055b3..22ae559 100644 --- a/server.js +++ b/server.js @@ -241,6 +241,7 @@ app.use((req, res, next) => { "/api/forgot-password/request-otp", "/api/forgot-password/verify-otp", "/api/csrf-token", + "/api/login/request-otp" ]; if (csrfExcludedPaths.includes(req.path)) {