GWM : login logic changed

This commit is contained in:
Gowtham M 2025-12-04 11:06:27 +05:30
parent 423bbbb61e
commit 33780616c3
9 changed files with 461 additions and 64 deletions

View File

@ -7,24 +7,6 @@ const User = db.user;
const EstablishmentUser = db.EstablishmentUser;
const Establishment = db.Establishment;
// Register new user
exports.register = async (req, res) => {
try {
const { name, email, password } = req.body;
if (!name || !email || !password)
return res.status(400).send({'status':"failed",'message':"All fields required",'data': ""});
const existing = await User.findOne({ where: { email } });
if (existing) res.status(400).send({'status':"failed",'message':"Email already used",'data': ""});
const hashedPassword = await bcrypt.hash(password, 10);
const newUser = await User.create({ name, email, password: hashedPassword });
res.status(201).send({'status':"success",'message':"User registered successfully",'data': newUser });
} catch (err) {
res.status(500).send({'status':"failed",'message':err.message });
}
};
//Admin user and Establishment user login
exports.login = async (req, res) => {
@ -91,7 +73,22 @@ exports.login = async (req, res) => {
expiresIn: "6h",
});
return res.status(200).json({ status: "success", message: "Login successful", data: token });
// Set token in HTTP-only cookie (IMPORTANT PART)
res.cookie("auth_token", token, {
httpOnly: true,
secure: process.env.NODE_ENV === "production", // true in prod (HTTPS)
sameSite: "lax", // or "strict" if suitable
maxAge: 6 * 60 * 60 * 1000, // 6 hours in ms
});
// Optionally return minimal user info (WITHOUT password)
return res.status(200).json({
status: "success",
message: "Login successful",
data: tokenData,
});
// return res.status(200).json({ status: "success", message: "Login successful", data: token });
} catch (err) {
return res.status(500).json({
@ -101,6 +98,40 @@ exports.login = async (req, res) => {
}
};
//logout
exports.logout = (req, res) => {
res.clearCookie("auth_token", {
httpOnly: true,
secure: process.env.NODE_ENV === "production",
sameSite: "lax",
});
return res.status(200).json({
status: "success",
message: "Logged out successfully",
});
};
// Register new user
exports.register = async (req, res) => {
try {
const { name, email, password } = req.body;
if (!name || !email || !password)
return res.status(400).send({'status':"failed",'message':"All fields required",'data': ""});
const existing = await User.findOne({ where: { email } });
if (existing) res.status(400).send({'status':"failed",'message':"Email already used",'data': ""});
const hashedPassword = await bcrypt.hash(password, 10);
const newUser = await User.create({ name, email, password: hashedPassword });
res.status(201).send({'status':"success",'message':"User registered successfully",'data': newUser });
} catch (err) {
res.status(500).send({'status':"failed",'message':err.message });
}
};
// Login user
// exports.login = async (req, res) => {
// try {

View File

@ -34,6 +34,20 @@ exports.testEmail = async (req, res) => {
exports.createEstablishment = async (req, res) => {
try {
// convert empty "" → null BEFORE destructure
[
"establishment_code",
"factory_name",
"permanent_factory_code",
"industry_code",
"industry_code_production",
"license_number",
"isic_code"
].forEach(key => {
if (req.body[key] === "") req.body[key] = null;
});
const {
establishment_code,
factory_name,
@ -81,6 +95,7 @@ exports.createEstablishment = async (req, res) => {
establishment_products
} = req.body;
// Basic Validation
if (!establishment_code || !factory_name || !establishment_user) {
return res.status(400).send({
@ -585,6 +600,20 @@ exports.getEstablishmentById = async (req, res) => {
// Update establishment
exports.updateEstablishment = async (req, res) => {
try {
// convert empty "" → null BEFORE destructure
[
"establishment_code",
"factory_name",
"permanent_factory_code",
"industry_code",
"industry_code_production",
"license_number",
"isic_code"
].forEach(key => {
if (req.body[key] === "") req.body[key] = null;
});
const { id } = req.params;
const { establishment_products, establishment_user, ...estData } = req.body;
const user = await EstablishmentUser.findOne({where:{establishment_id:id}});

View File

@ -1,18 +1,87 @@
const db = require("../models");
const NotificationTemplate = db.NotificationTemplate;
const { sanitizeHtml } = require("../utils/sanitize");
// Create template
exports.createTemplate = async (req, res) => {
try {
req.body.created_by = req.body.created_by || req.user.id;
const template = await NotificationTemplate.create(req.body);
res.status(201).send({
try {
const { title , template_code, subject, body_html , created_by } = req.body;
if (!title || !template_code || !subject || !body_html ) {
return res.status(400).json({
status: "failed",
message: "Missing required fields",
});
}
// sanitize input
const cleanHtml = sanitizeHtml(body_html);
const template = await NotificationTemplate.create({
title,
template_code,
subject,
body_html: cleanHtml,
created_by: created_by || req.user?.id || null,
});
return res.status(201).json({
status: "success",
message: "Template created successfully",
data: template,
data: {
id: template.id,
template_code: template.template_code,
subject: template.subject
// DO NOT return HTML to avoid XSS
},
});
} catch (err) {
res.status(500).send({ status: "failed", message: err.message });
res.status(500).json({ status: "failed", message: err.message });
}
};
// Update template
exports.updateTemplate = async (req, res) => {
try {
const id = req.params.id;
// whitelist fields
const updateData = {};
if (req.body.title) updateData.title = req.body.title;
if (req.body.subject) updateData.subject = req.body.subject;
// sanitize HTML if provided
if (req.body.body_html) {
updateData.body_html = sanitizeHtml(req.body.body_html);
}
updateData.updated_by = req.body.updated_by || req.user?.id || null;
updateData.updated_at = new Date();
// run update
const [updated] = await NotificationTemplate.update(updateData, {
where: { id }
});
if (!updated) {
return res.status(404).json({
status: "failed",
message: "Template not found"
});
}
return res.status(200).json({
status: "success",
message: "Template updated successfully"
});
} catch (err) {
return res.status(500).json({
status: "failed",
message: err.message
});
}
};
@ -49,29 +118,6 @@ exports.getTemplateById = async (req, res) => {
}
};
// Update template
exports.updateTemplate = async (req, res) => {
try {
req.body.updated_by = req.body.updated_by || req.user.id;
req.body.updated_at = req.body.updated_at || new Date();
const [updated] = await NotificationTemplate.update(req.body, {
where: { id: req.params.id },
});
if (!updated)
return res
.status(404)
.send({ status: "failed", message: "Template not found" });
res
.status(200)
.send({ status: "success", message: "Updated successfully" });
} catch (err) {
res.status(500).send({ status: "failed", message: err.message });
}
};
// Delete template
exports.deleteTemplate = async (req, res) => {
try {

View File

@ -1,15 +1,45 @@
const jwt = require("jsonwebtoken");
require("dotenv").config();
module.exports = function (req, res, next) {
const authHeader = req.headers["authorization"];
const token = authHeader && authHeader.split(" ")[1]; // Expect "Bearer <token>"
// module.exports = function (req, res, next) {
// const authHeader = req.headers["authorization"];
// const token = authHeader && authHeader.split(" ")[1]; // Expect "Bearer <token>"
if (!token) return res.status(403).json({ message: "Access denied, token missing" });
// if (!token) return res.status(403).json({ message: "Access denied, token missing" });
jwt.verify(token, process.env.JWT_SECRET, (err, decoded) => {
if (err) return res.status(401).json({ message: "Invalid or expired token" });
// jwt.verify(token, process.env.JWT_SECRET, (err, decoded) => {
// if (err) return res.status(401).json({ message: "Invalid or expired token" });
// req.user = decoded;
// next();
// });
// };
const authJWT = (req, res, next) => {
try {
const token =
req.cookies?.auth_token ||
(req.headers.authorization && req.headers.authorization.split(" ")[1]);
if (!token) {
return res
.status(401)
.json({ status: "failed", message: "Unauthorized: No token provided" });
}
console.log('token ='+token)
const decoded = jwt.verify(token, process.env.JWT_SECRET);
// Attach user info to req for downstream handlers
req.user = decoded;
next();
});
} catch (err) {
return res
.status(401)
.json({ status: "failed", message: "Unauthorized: Invalid token" });
}
};
module.exports = authJWT;

View File

@ -69,6 +69,10 @@ const upload = multer({ dest: "../writable/uploads/products_bulk_uploads_files"
/**
* @swagger
* components:
@ -201,7 +205,7 @@ router.post("/auth/login",[verifySignature], authController.login);
* tags: [Admin Users]
* security:
* - appSignature: []
* - bearerAuth: []
* cookieAuth: [] # or bearerAuth: [] if you use Authorization header
* responses:
* 201:
* description: Fetched successfully
@ -210,7 +214,7 @@ router.post("/auth/login",[verifySignature], authController.login);
* 500:
* description: Server error
*/
router.get("/admin_users", [verifySignature, verifyToken], adminUserController.getAllUsers);
router.get("/admin_users", [verifySignature , verifyToken], adminUserController.getAllUsers);
/**
* @swagger

12
app/utils/sanitize.js Normal file
View File

@ -0,0 +1,12 @@
const sanitize = require("sanitize-html");
exports.sanitizeHtml = (html = "") => {
return sanitize(html, {
allowedTags: sanitize.defaults.allowedTags.concat(["img"]),
allowedAttributes: {
"*": ["style", "class"],
img: ["src", "alt"]
},
disallowedTagsMode: "discard"
});
};

201
package-lock.json generated
View File

@ -10,6 +10,7 @@
"license": "ISC",
"dependencies": {
"bcryptjs": "^3.0.2",
"cookie-parser": "^1.4.7",
"cors": "^2.8.5",
"csv-parser": "^3.2.0",
"dotenv": "^17.2.3",
@ -23,6 +24,7 @@
"mysql2": "^3.15.2",
"nodemailer": "^7.0.10",
"nodemon": "^3.1.10",
"sanitize-html": "^2.17.0",
"sequelize": "^6.37.7",
"swagger-jsdoc": "^6.2.8",
"swagger-ui-express": "^5.0.1",
@ -677,6 +679,23 @@
"node": ">= 0.6"
}
},
"node_modules/cookie-parser": {
"version": "1.4.7",
"resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.7.tgz",
"integrity": "sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw==",
"dependencies": {
"cookie": "0.7.2",
"cookie-signature": "1.0.6"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/cookie-parser/node_modules/cookie-signature": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
},
"node_modules/cookie-signature": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz",
@ -757,6 +776,14 @@
}
}
},
"node_modules/deepmerge": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
"integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/denque": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz",
@ -784,6 +811,57 @@
"node": ">=6.0.0"
}
},
"node_modules/dom-serializer": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
"integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
"dependencies": {
"domelementtype": "^2.3.0",
"domhandler": "^5.0.2",
"entities": "^4.2.0"
},
"funding": {
"url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
}
},
"node_modules/domelementtype": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
"integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/fb55"
}
]
},
"node_modules/domhandler": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
"integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
"dependencies": {
"domelementtype": "^2.3.0"
},
"engines": {
"node": ">= 4"
},
"funding": {
"url": "https://github.com/fb55/domhandler?sponsor=1"
}
},
"node_modules/domutils": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz",
"integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==",
"dependencies": {
"dom-serializer": "^2.0.0",
"domelementtype": "^2.3.0",
"domhandler": "^5.0.3"
},
"funding": {
"url": "https://github.com/fb55/domutils?sponsor=1"
}
},
"node_modules/dotenv": {
"version": "17.2.3",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz",
@ -882,6 +960,17 @@
"once": "^1.4.0"
}
},
"node_modules/entities": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
"engines": {
"node": ">=0.12"
},
"funding": {
"url": "https://github.com/fb55/entities?sponsor=1"
}
},
"node_modules/es-define-property": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
@ -914,6 +1003,17 @@
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
"integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
},
"node_modules/escape-string-regexp": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/esutils": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
@ -1249,6 +1349,24 @@
"node": ">=18.0.0"
}
},
"node_modules/htmlparser2": {
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz",
"integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==",
"funding": [
"https://github.com/fb55/htmlparser2?sponsor=1",
{
"type": "github",
"url": "https://github.com/sponsors/fb55"
}
],
"dependencies": {
"domelementtype": "^2.3.0",
"domhandler": "^5.0.3",
"domutils": "^3.0.1",
"entities": "^4.4.0"
}
},
"node_modules/http-errors": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
@ -1381,6 +1499,14 @@
"node": ">=0.12.0"
}
},
"node_modules/is-plain-object": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/is-promise": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz",
@ -1942,6 +2068,23 @@
"node": ">=12.0.0"
}
},
"node_modules/nanoid": {
"version": "3.3.11",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
"integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"bin": {
"nanoid": "bin/nanoid.cjs"
},
"engines": {
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
"node_modules/negotiator": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz",
@ -2060,6 +2203,11 @@
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="
},
"node_modules/parse-srcset": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/parse-srcset/-/parse-srcset-1.0.2.tgz",
"integrity": "sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q=="
},
"node_modules/parseurl": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
@ -2090,6 +2238,11 @@
"resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.9.1.tgz",
"integrity": "sha512-nkc6NpDcvPVpZXxrreI/FOtX3XemeLl8E0qFr6F2Lrm/I8WOnaWNhIPK2Z7OHpw7gh5XJThi6j6ppgNoaT1w4w=="
},
"node_modules/picocolors": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="
},
"node_modules/picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
@ -2101,6 +2254,33 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/postcss": {
"version": "8.5.6",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
"integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
"funding": [
{
"type": "opencollective",
"url": "https://opencollective.com/postcss/"
},
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/postcss"
},
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"dependencies": {
"nanoid": "^3.3.11",
"picocolors": "^1.1.1",
"source-map-js": "^1.2.1"
},
"engines": {
"node": "^10 || ^12 || >=14"
}
},
"node_modules/process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
@ -2289,6 +2469,19 @@
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"node_modules/sanitize-html": {
"version": "2.17.0",
"resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-2.17.0.tgz",
"integrity": "sha512-dLAADUSS8rBwhaevT12yCezvioCA+bmUTPH/u57xKPT8d++voeYE6HeluA/bPbQ15TwDBG2ii+QZIEmYx8VdxA==",
"dependencies": {
"deepmerge": "^4.2.2",
"escape-string-regexp": "^4.0.0",
"htmlparser2": "^8.0.0",
"is-plain-object": "^5.0.0",
"parse-srcset": "^1.0.2",
"postcss": "^8.3.11"
}
},
"node_modules/saxes": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz",
@ -2509,6 +2702,14 @@
"node": ">=10"
}
},
"node_modules/source-map-js": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/sqlstring": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz",

View File

@ -12,6 +12,7 @@
"license": "ISC",
"dependencies": {
"bcryptjs": "^3.0.2",
"cookie-parser": "^1.4.7",
"cors": "^2.8.5",
"csv-parser": "^3.2.0",
"dotenv": "^17.2.3",
@ -25,6 +26,7 @@
"mysql2": "^3.15.2",
"nodemailer": "^7.0.10",
"nodemon": "^3.1.10",
"sanitize-html": "^2.17.0",
"sequelize": "^6.37.7",
"swagger-jsdoc": "^6.2.8",
"swagger-ui-express": "^5.0.1",

View File

@ -1,21 +1,52 @@
const express = require("express");
const cors = require("cors");
const helmet = require("helmet");
const helmet = require("helmet");
const morgan = require("morgan");
const swaggerUi = require("swagger-ui-express");
const swaggerJsdoc = require("swagger-jsdoc");
const routes = require("./app/routes/routes");
const db = require("./app/models");
const path = require("path");
const cookieParser = require("cookie-parser");
require("dotenv").config();
const app = express();
app.use(express.json());
app.use(cors());
app.use(helmet());
app.use(morgan("dev"));
app.use(cookieParser());
// // Swagger setup
// const swaggerOptions = {
// definition: {
// openapi: "3.0.0",
// info: {
// title: "FCSC IPI Survey",
// version: "1.0.0",
// description: "Federal Competitiveness and Statistics Centre (FCSC) - Industrial Production Index (IPI)",
// },
// components: {
// securitySchemes: {
// bearerAuth: {
// type: "http",
// scheme: "bearer",
// bearerFormat: "JWT",
// },
// },
// },
// security: [
// {
// bearerAuth: [],
// },
// ],
// },
// apis: ["./app/routes/*.js"],
// };
// const swaggerDocs = swaggerJsdoc(swaggerOptions);
// app.use("/api-docs", swaggerUi.serve, swaggerUi.setup(swaggerDocs));
// Swagger setup
const swaggerOptions = {
definition: {
@ -27,23 +58,34 @@ const swaggerOptions = {
},
components: {
securitySchemes: {
// Optional: Still support Bearer for Swagger-only testing
bearerAuth: {
type: "http",
scheme: "bearer",
bearerFormat: "JWT",
},
appSignature: {
type: "apiKey",
in: "header",
name: "x-app-signature"
}
},
},
security: [
{
bearerAuth: [],
},
],
},
apis: ["./app/routes/*.js"],
};
const swaggerDocs = swaggerJsdoc(swaggerOptions);
app.use("/api-docs", swaggerUi.serve, swaggerUi.setup(swaggerDocs));
app.use(
"/api-docs",
swaggerUi.serve,
swaggerUi.setup(swaggerDocs, {
swaggerOptions: {
withCredentials: true, // 🔥 VERY IMPORTANT
},
})
);
// Routes