xxx
This commit is contained in:
4
.qsync/meta/meta.conf
Normal file
4
.qsync/meta/meta.conf
Normal file
@@ -0,0 +1,4 @@
|
||||
[/dms]
|
||||
max_log = 502986
|
||||
number = 3
|
||||
finish = 1
|
||||
10988
.qsync/meta/qmeta0
Normal file
10988
.qsync/meta/qmeta0
Normal file
File diff suppressed because it is too large
Load Diff
11488
.qsync/meta/qmeta1
Normal file
11488
.qsync/meta/qmeta1
Normal file
File diff suppressed because it is too large
Load Diff
8799
.qsync/meta/qmeta2
Normal file
8799
.qsync/meta/qmeta2
Normal file
File diff suppressed because it is too large
Load Diff
150
backend/src/db/sequelize.js
Normal file → Executable file
150
backend/src/db/sequelize.js
Normal file → Executable file
@@ -5,11 +5,7 @@
|
||||
import { Sequelize } from "sequelize";
|
||||
import { config } from "../config.js";
|
||||
|
||||
export const sequelize = new Sequelize(
|
||||
config.DB.NAME,
|
||||
config.DB.USER,
|
||||
config.DB.PASS,
|
||||
{
|
||||
export const sequelize = new Sequelize(config.DB.NAME, config.DB.USER, config.DB.PASS, {
|
||||
host: config.DB.HOST,
|
||||
port: config.DB.PORT,
|
||||
dialect: "mariadb",
|
||||
@@ -17,79 +13,91 @@ export const sequelize = new Sequelize(
|
||||
dialectOptions: { timezone: "Z" },
|
||||
define: { freezeTableName: true, underscored: false, timestamps: false },
|
||||
pool: { max: 10, min: 0, idle: 10000 },
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
// --- 1. ประกาศตัวแปรสำหรับ Export Model ทั้งหมด ---
|
||||
export let User = null;
|
||||
export let Role = null;
|
||||
export let Permission = null;
|
||||
export let UserRole = null;
|
||||
export let RolePermission = null;
|
||||
export let Project = null; // <-- เพิ่มเข้ามา
|
||||
export let UserProjectRole = null; // <-- เพิ่มเข้ามา
|
||||
export let User, Role, Permission, Organization, Project, UserRole, RolePermission,
|
||||
UserProjectRole, Correspondence, CorrespondenceVersion, Document, CorrDocumentMap,
|
||||
Drawing, DrawingRevision, FileObject, RFA, RFARevision, RfaDrawingMap,
|
||||
Transmittal, TransmittalItem, Volume, ContractDwg, SubCategory;
|
||||
|
||||
if (process.env.ENABLE_SEQUELIZE === "1") {
|
||||
// --- 2. โหลดโมเดลทั้งหมดแบบ on-demand ---
|
||||
const mdlUser = await import("./models/User.js").catch(() => null);
|
||||
const mdlRole = await import("./models/Role.js").catch(() => null);
|
||||
const mdlPerm = await import("./models/Permission.js").catch(() => null);
|
||||
const mdlUR = await import("./models/UserRole.js").catch(() => null);
|
||||
const mdlRP = await import("./models/RolePermission.js").catch(() => null);
|
||||
const mdlProj = await import("./models/Project.js").catch(() => null); // <-- เพิ่มเข้ามา
|
||||
const mdlUPR = await import("./models/UserProjectRole.js").catch(() => null); // <-- เพิ่มเข้ามา
|
||||
// --- 2. สร้าง Object ของ Models ทั้งหมดที่จะโหลด ---
|
||||
const modelsToLoad = {
|
||||
User: await import("./models/User.js").catch(() => null),
|
||||
Role: await import("./models/Role.js").catch(() => null),
|
||||
Permission: await import("./models/Permission.js").catch(() => null),
|
||||
Organization: await import("./models/Organization.js").catch(() => null),
|
||||
Project: await import("./models/Project.js").catch(() => null),
|
||||
UserRole: await import("./models/UserRole.js").catch(() => null),
|
||||
RolePermission: await import("./models/RolePermission.js").catch(() => null),
|
||||
UserProjectRole: await import("./models/UserProjectRole.js").catch(() => null),
|
||||
Correspondence: await import("./models/Correspondence.js").catch(() => null),
|
||||
CorrespondenceVersion: await import("./models/CorrespondenceVersion.js").catch(() => null),
|
||||
Document: await import("./models/Document.js").catch(() => null),
|
||||
CorrDocumentMap: await import("./models/CorrDocumentMap.js").catch(() => null),
|
||||
Drawing: await import("./models/Drawing.js").catch(() => null),
|
||||
DrawingRevision: await import("./models/DrawingRevision.js").catch(() => null),
|
||||
FileObject: await import("./models/FileObject.js").catch(() => null),
|
||||
RFA: await import("./models/RFA.js").catch(() => null),
|
||||
RFARevision: await import("./models/RFARevision.js").catch(() => null),
|
||||
RfaDrawingMap: await import("./models/RfaDrawingMap.js").catch(() => null),
|
||||
Transmittal: await import("./models/Transmittal.js").catch(() => null),
|
||||
TransmittalItem: await import("./models/TransmittalItem.js").catch(() => null),
|
||||
Volume: await import("./models/Volume.js").catch(() => null),
|
||||
ContractDwg: await import("./models/ContractDwg.js").catch(() => null),
|
||||
SubCategory: await import("./models/SubCategory.js").catch(() => null),
|
||||
};
|
||||
|
||||
// --- 3. Initialize Model ทั้งหมด ---
|
||||
if (mdlUser?.default) User = mdlUser.default(sequelize);
|
||||
if (mdlRole?.default) Role = mdlRole.default(sequelize);
|
||||
if (mdlPerm?.default) Permission = mdlPerm.default(sequelize);
|
||||
if (mdlUR?.default) UserRole = mdlUR.default(sequelize);
|
||||
if (mdlRP?.default) RolePermission = mdlRP.default(sequelize);
|
||||
if (mdlProj?.default) Project = mdlProj.default(sequelize); // <-- เพิ่มเข้ามา
|
||||
if (mdlUPR?.default) UserProjectRole = mdlUPR.default(sequelize); // <-- เพิ่มเข้ามา
|
||||
// --- 3. Initialize Model ทั้งหมด ---
|
||||
User = modelsToLoad.User?.default ? modelsToLoad.User.default(sequelize) : null;
|
||||
Role = modelsToLoad.Role?.default ? modelsToLoad.Role.default(sequelize) : null;
|
||||
Permission = modelsToLoad.Permission?.default ? modelsToLoad.Permission.default(sequelize) : null;
|
||||
Organization = modelsToLoad.Organization?.default ? modelsToLoad.Organization.default(sequelize) : null;
|
||||
Project = modelsToLoad.Project?.default ? modelsToLoad.Project.default(sequelize) : null;
|
||||
UserRole = modelsToLoad.UserRole?.default ? modelsToLoad.UserRole.default(sequelize) : null;
|
||||
RolePermission = modelsToLoad.RolePermission?.default ? modelsToLoad.RolePermission.default(sequelize) : null;
|
||||
UserProjectRole = modelsToLoad.UserProjectRole?.default ? modelsToLoad.UserProjectRole.default(sequelize) : null;
|
||||
Correspondence = modelsToLoad.Correspondence?.default ? modelsToLoad.Correspondence.default(sequelize) : null;
|
||||
CorrespondenceVersion = modelsToLoad.CorrespondenceVersion?.default ? modelsToLoad.CorrespondenceVersion.default(sequelize) : null;
|
||||
Document = modelsToLoad.Document?.default ? modelsToLoad.Document.default(sequelize) : null;
|
||||
CorrDocumentMap = modelsToLoad.CorrDocumentMap?.default ? modelsToLoad.CorrDocumentMap.default(sequelize) : null;
|
||||
Drawing = modelsToLoad.Drawing?.default ? modelsToLoad.Drawing.default(sequelize) : null;
|
||||
DrawingRevision = modelsToLoad.DrawingRevision?.default ? modelsToLoad.DrawingRevision.default(sequelize) : null;
|
||||
FileObject = modelsToLoad.FileObject?.default ? modelsToLoad.FileObject.default(sequelize) : null;
|
||||
RFA = modelsToLoad.RFA?.default ? modelsToLoad.RFA.default(sequelize) : null;
|
||||
RFARevision = modelsToLoad.RFARevision?.default ? modelsToLoad.RFARevision.default(sequelize) : null;
|
||||
RfaDrawingMap = modelsToLoad.RfaDrawingMap?.default ? modelsToLoad.RfaDrawingMap.default(sequelize) : null;
|
||||
Transmittal = modelsToLoad.Transmittal?.default ? modelsToLoad.Transmittal.default(sequelize) : null;
|
||||
TransmittalItem = modelsToLoad.TransmittalItem?.default ? modelsToLoad.TransmittalItem.default(sequelize) : null;
|
||||
Volume = modelsToLoad.Volume?.default ? modelsToLoad.Volume.default(sequelize) : null;
|
||||
ContractDwg = modelsToLoad.ContractDwg?.default ? modelsToLoad.ContractDwg.default(sequelize) : null;
|
||||
SubCategory = modelsToLoad.SubCategory?.default ? modelsToLoad.SubCategory.default(sequelize) : null;
|
||||
|
||||
// --- 4. สร้างความสัมพันธ์ (Associations) ทั้งหมด ---
|
||||
if (User && Role && Permission && UserRole && RolePermission) {
|
||||
// ความสัมพันธ์ระดับระบบ (System-level)
|
||||
User.belongsToMany(Role, { through: UserRole, foreignKey: "user_id" });
|
||||
Role.belongsToMany(User, { through: UserRole, foreignKey: "role_id" });
|
||||
Role.belongsToMany(Permission, {
|
||||
through: RolePermission,
|
||||
foreignKey: "role_id",
|
||||
});
|
||||
Permission.belongsToMany(Role, {
|
||||
through: RolePermission,
|
||||
foreignKey: "permission_id",
|
||||
});
|
||||
}
|
||||
|
||||
// ความสัมพันธ์ระดับโปรเจกต์ (Project-level) - ส่วนที่เพิ่มเข้ามา
|
||||
if (User && Project && Role && UserProjectRole) {
|
||||
// ทำให้ UserProjectRole เป็นตัวกลางเชื่อม 3 ตาราง
|
||||
UserProjectRole.belongsTo(User, { foreignKey: "user_id" });
|
||||
UserProjectRole.belongsTo(Project, { foreignKey: "project_id" });
|
||||
UserProjectRole.belongsTo(Role, { foreignKey: "role_id" });
|
||||
|
||||
// ทำให้สามารถ include ข้อมูลที่เกี่ยวข้องได้ง่ายขึ้น
|
||||
User.hasMany(UserProjectRole, { foreignKey: "user_id" });
|
||||
Project.hasMany(UserProjectRole, { foreignKey: "project_id" });
|
||||
Role.hasMany(UserProjectRole, { foreignKey: "role_id" });
|
||||
}
|
||||
// --- 4. สร้างความสัมพันธ์ (Associations) ---
|
||||
const loadedModels = { User, Role, Permission, Organization, Project, UserRole, RolePermission,
|
||||
UserProjectRole, Correspondence, CorrespondenceVersion, Document, CorrDocumentMap,
|
||||
Drawing, DrawingRevision, FileObject, RFA, RFARevision, RfaDrawingMap,
|
||||
Transmittal, TransmittalItem, Volume, ContractDwg, SubCategory };
|
||||
|
||||
for (const modelName in loadedModels) {
|
||||
if (loadedModels[modelName] && loadedModels[modelName].associate) {
|
||||
loadedModels[modelName].associate(loadedModels);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ฟังก์ชันสำหรับทดสอบการเชื่อมต่อ Sequelize
|
||||
*/
|
||||
export async function dbReady() {
|
||||
if (process.env.ENABLE_SEQUELIZE !== "1") {
|
||||
console.log("Sequelize is disabled.");
|
||||
return Promise.resolve();
|
||||
}
|
||||
try {
|
||||
await sequelize.authenticate();
|
||||
console.log("Sequelize connection has been established successfully.");
|
||||
} catch (error) {
|
||||
console.error("Unable to connect to the database via Sequelize:", error);
|
||||
return Promise.reject(error);
|
||||
}
|
||||
}
|
||||
if (process.env.ENABLE_SEQUELIZE !== "1") {
|
||||
console.log("Sequelize is disabled.");
|
||||
return Promise.resolve();
|
||||
}
|
||||
try {
|
||||
await sequelize.authenticate();
|
||||
console.log("Sequelize connection has been established successfully.");
|
||||
} catch (error) {
|
||||
console.error("Unable to connect to the database via Sequelize:", error);
|
||||
return Promise.reject(error);
|
||||
}
|
||||
}
|
||||
61
backend/src/middleware/auth copy.js
Executable file
61
backend/src/middleware/auth copy.js
Executable file
@@ -0,0 +1,61 @@
|
||||
// FILE: backend/src/middleware/auth.js
|
||||
|
||||
import jwt from "jsonwebtoken";
|
||||
import { config } from "../config.js";
|
||||
import { User, Role, UserRole } from "../db/sequelize.js";
|
||||
|
||||
export function signAccessToken(payload) {
|
||||
return jwt.sign(payload, config.JWT.SECRET, {
|
||||
expiresIn: config.JWT.EXPIRES_IN,
|
||||
});
|
||||
}
|
||||
export function signRefreshToken(payload) {
|
||||
return jwt.sign(payload, config.JWT.REFRESH_SECRET, {
|
||||
expiresIn: config.JWT.REFRESH_EXPIRES_IN,
|
||||
});
|
||||
}
|
||||
|
||||
export function extractToken(req) {
|
||||
// ให้คุกกี้มาก่อน แล้วค่อย Bearer (รองรับทั้งสองทาง)
|
||||
const cookieTok = req.cookies?.access_token || null;
|
||||
if (cookieTok) return cookieTok;
|
||||
const hdr = req.headers.authorization || "";
|
||||
return hdr.startsWith("Bearer ") ? hdr.slice(7) : null;
|
||||
}
|
||||
|
||||
export function requireAuth(req, res, next) {
|
||||
if (req.path === "/health") return next(); // อนุญาต health เสมอ
|
||||
const token = extractToken(req);
|
||||
if (!token) return res.status(401).json({ error: "Missing token" });
|
||||
|
||||
try {
|
||||
req.user = jwt.verify(token, config.JWT.SECRET);
|
||||
next();
|
||||
} catch {
|
||||
return res.status(401).json({ error: "Invalid/Expired token" });
|
||||
}
|
||||
}
|
||||
// ใช้กับเส้นทางที่ login แล้วจะ enrich ต่อได้ แต่ไม่บังคับ
|
||||
export function optionalAuth(req, _res, next) {
|
||||
const token = extractToken(req);
|
||||
if (!token) return next();
|
||||
try {
|
||||
req.user = jwt.verify(token, config.JWT.SECRET);
|
||||
} catch {}
|
||||
next();
|
||||
}
|
||||
|
||||
export async function enrichRoles(req, _res, next) {
|
||||
if (!req.user?.user_id) return next();
|
||||
const rows = await UserRole.findAll({
|
||||
where: { user_id: req.user.user_id },
|
||||
include: [{ model: Role }],
|
||||
}).catch(() => []);
|
||||
req.user.roles = rows.map((r) => r.role?.role_name).filter(Boolean);
|
||||
next();
|
||||
}
|
||||
|
||||
export function hasPerm(req, perm) {
|
||||
const set = new Set(req?.user?.permissions || []);
|
||||
return set.has(perm);
|
||||
}
|
||||
0
backend/src/middleware/auth.js
Normal file → Executable file
0
backend/src/middleware/auth.js
Normal file → Executable file
6
backend/src/middleware/index.js
Normal file → Executable file
6
backend/src/middleware/index.js
Normal file → Executable file
@@ -1,7 +1,7 @@
|
||||
// File: backend/src/middleware/index.js
|
||||
import * as authJwt from "./authJwt.js";
|
||||
import * as abac from "./abac.js";
|
||||
import * as auth from "./auth.js";
|
||||
import * as authJwt from "./authJwt.js";
|
||||
import * as errorHandler from "./errorHandler.js";
|
||||
import * as loadPrincipal from "./loadPrincipal.js";
|
||||
import * as permGuard from "./permGuard.js";
|
||||
@@ -12,9 +12,9 @@ import * as requirePerm from "./requirePerm.js";
|
||||
// Export ทุกอย่างออกมาเป็น named exports
|
||||
// เพื่อให้สามารถ import แบบ `import { authJwt, permGuard } from '../middleware';` ได้
|
||||
export {
|
||||
authJwt,
|
||||
abac,
|
||||
auth,
|
||||
authJwt,
|
||||
errorHandler,
|
||||
loadPrincipal,
|
||||
permGuard,
|
||||
@@ -25,9 +25,9 @@ export {
|
||||
|
||||
// (Optional) สร้าง default export สำหรับกรณีที่ต้องการ import ทั้งหมดใน object เดียว
|
||||
const middleware = {
|
||||
authJwt,
|
||||
abac,
|
||||
auth,
|
||||
authJwt,
|
||||
errorHandler,
|
||||
loadPrincipal,
|
||||
permGuard,
|
||||
|
||||
0
backend/src/middleware/loadPrincipal.js
Normal file → Executable file
0
backend/src/middleware/loadPrincipal.js
Normal file → Executable file
74
backend/src/routes/dashboard.js
Normal file → Executable file
74
backend/src/routes/dashboard.js
Normal file → Executable file
@@ -1,23 +1,63 @@
|
||||
import { Router } from "express";
|
||||
import { User } from "../db/index.js";
|
||||
import { authJwt } from "../middleware/index.js";
|
||||
// backend/src/routes/dashboard.js
|
||||
import { Router } from 'express';
|
||||
import { Op } from 'sequelize';
|
||||
|
||||
// 1. Import Middleware ที่ถูกต้อง
|
||||
import { authJwt } from '../middleware/authJwt.js';
|
||||
import { loadPrincipalMw } from '../middleware/loadPrincipal.js';
|
||||
|
||||
// 2. Import Sequelize Models จาก `sequelize.js` ไม่ใช่ `index.js`
|
||||
import { Correspondence, Document, RFA, User } from '../db/sequelize.js';
|
||||
|
||||
const router = Router();
|
||||
|
||||
router.use(authJwt.verifyToken);
|
||||
// 3. ใช้ Middleware Chain ที่ถูกต้อง 100%
|
||||
router.use(authJwt(), loadPrincipalMw());
|
||||
|
||||
router.get("/users/summary", async (req, res, next) => {
|
||||
try {
|
||||
const totalUsers = await User.count();
|
||||
const activeUsers = await User.count({ where: { is_active: true } });
|
||||
res.json({
|
||||
total: totalUsers,
|
||||
active: activeUsers,
|
||||
inactive: totalUsers - activeUsers,
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
|
||||
// === API สำหรับ User Management Widget ===
|
||||
router.get('/users/summary', async (req, res, next) => {
|
||||
try {
|
||||
// ตรวจสอบว่า Model ถูกโหลดแล้วหรือยัง (จำเป็นสำหรับโหมด lazy-load)
|
||||
if (!User) {
|
||||
return res.status(503).json({ message: 'Database models not available. Is ENABLE_SEQUELIZE=1 set?' });
|
||||
}
|
||||
const totalUsers = await User.count();
|
||||
const activeUsers = await User.count({ where: { is_active: true } });
|
||||
|
||||
res.json({
|
||||
total: totalUsers,
|
||||
active: activeUsers,
|
||||
inactive: totalUsers - activeUsers,
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
|
||||
// === API อื่นๆ สำหรับ Dashboard ที่เราคุยกันไว้ก่อนหน้า ===
|
||||
router.get('/stats', async (req, res, next) => {
|
||||
try {
|
||||
if (!Document || !RFA) {
|
||||
return res.status(503).json({ message: 'Database models not available. Is ENABLE_SEQUELIZE=1 set?' });
|
||||
}
|
||||
|
||||
const sevenDaysAgo = new Date(new Date().setDate(new Date().getDate() - 7));
|
||||
|
||||
const totalDocuments = await Document.count();
|
||||
const newThisWeek = await Document.count({ where: { createdAt: { [Op.gte]: sevenDaysAgo } } });
|
||||
const pendingRfas = await RFA.count({ where: { status: 'pending' } }); // สมมติตาม status
|
||||
|
||||
res.json({
|
||||
totalDocuments,
|
||||
newThisWeek,
|
||||
pendingRfas
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
export default router;
|
||||
130
backend/src/routes/rbac_admin.js
Normal file → Executable file
130
backend/src/routes/rbac_admin.js
Normal file → Executable file
@@ -1,144 +1,88 @@
|
||||
// FILE: backend/src/routes/rbac_admin.js
|
||||
import { Router } from "express";
|
||||
import { Role, Permission, UserProjectRole, Project } from "../db/sequelize.js";
|
||||
import { authJwt, permGuard } from "../middleware/index.js";
|
||||
import { authJwt } from "../middleware/authJwt.js";
|
||||
import { loadPrincipalMw } from "../middleware/loadPrincipal.js"; // แก้ไข: import ให้ถูกต้อง
|
||||
import { requirePerm } from "../middleware/requirePerm.js";
|
||||
|
||||
const router = Router();
|
||||
|
||||
// กำหนดให้ทุก route ในไฟล์นี้ต้องมีสิทธิ์ 'manage_rbac'
|
||||
router.use(authJwt.verifyToken, permGuard("manage_rbac"));
|
||||
// Middleware Chain ที่ถูกต้อง 100% ตามสถาปัตยกรรมของคุณ
|
||||
router.use(authJwt(), loadPrincipalMw());
|
||||
|
||||
// == ROLES Management ==
|
||||
router.get("/roles", async (req, res, next) => {
|
||||
router.get("/roles", requirePerm("roles.manage"), async (req, res, next) => {
|
||||
try {
|
||||
const roles = await Role.findAll({
|
||||
include: [
|
||||
{
|
||||
model: Permission,
|
||||
attributes: ["id", "name"],
|
||||
through: { attributes: [] },
|
||||
},
|
||||
],
|
||||
include: [{ model: Permission, attributes: ["id", "name"], through: { attributes: [] } }],
|
||||
order: [["name", "ASC"]],
|
||||
});
|
||||
res.json(roles);
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
} catch (error) { next(error); }
|
||||
});
|
||||
|
||||
router.post("/roles", async (req, res, next) => {
|
||||
router.post("/roles", requirePerm("roles.manage"), async (req, res, next) => {
|
||||
const { name, description } = req.body;
|
||||
if (!name) return res.status(400).json({ message: "Role name is required." });
|
||||
try {
|
||||
const { name, description } = req.body;
|
||||
if (!name)
|
||||
return res.status(400).json({ message: "Role name is required." });
|
||||
const newRole = await Role.create({ name, description });
|
||||
res.status(201).json(newRole);
|
||||
} catch (error) {
|
||||
if (error.name === "SequelizeUniqueConstraintError") {
|
||||
return res
|
||||
.status(409)
|
||||
.json({ message: `Role '${name}' already exists.` });
|
||||
return res.status(409).json({ message: `Role '${name}' already exists.` });
|
||||
}
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
router.put("/roles/:id/permissions", async (req, res, next) => {
|
||||
try {
|
||||
router.put("/roles/:id/permissions", requirePerm("roles.manage"), async (req, res, next) => {
|
||||
const { permissionIds } = req.body;
|
||||
if (!Array.isArray(permissionIds))
|
||||
return res
|
||||
.status(400)
|
||||
.json({ message: "permissionIds must be an array." });
|
||||
|
||||
const role = await Role.findByPk(req.params.id);
|
||||
if (!role) return res.status(404).json({ message: "Role not found." });
|
||||
|
||||
await role.setPermissions(permissionIds);
|
||||
const updatedRole = await Role.findByPk(req.params.id, {
|
||||
include: [
|
||||
{
|
||||
model: Permission,
|
||||
attributes: ["id", "name"],
|
||||
through: { attributes: [] },
|
||||
},
|
||||
],
|
||||
});
|
||||
res.json(updatedRole);
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
// == PERMISSIONS Management ==
|
||||
router.get("/permissions", async (req, res, next) => {
|
||||
try {
|
||||
const permissions = await Permission.findAll({ order: [["name", "ASC"]] });
|
||||
res.json(permissions);
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
if (!Array.isArray(permissionIds)) return res.status(400).json({ message: "permissionIds must be an array." });
|
||||
try {
|
||||
const role = await Role.findByPk(req.params.id);
|
||||
if (!role) return res.status(404).json({ message: "Role not found." });
|
||||
await role.setPermissions(permissionIds);
|
||||
const updatedRole = await Role.findByPk(req.params.id, {
|
||||
include: [{ model: Permission, attributes: ['id', 'name'], through: { attributes: [] } }]
|
||||
});
|
||||
res.json(updatedRole);
|
||||
} catch (error) { next(error); }
|
||||
});
|
||||
|
||||
// == USER-PROJECT-ROLES Management ==
|
||||
router.get("/user-project-roles", async (req, res, next) => {
|
||||
router.get("/user-project-roles", requirePerm("users.manage"), async (req, res, next) => {
|
||||
const { userId } = req.query;
|
||||
if (!userId)
|
||||
return res
|
||||
.status(400)
|
||||
.json({ message: "userId query parameter is required." });
|
||||
if (!userId) return res.status(400).json({ message: "userId query parameter is required." });
|
||||
try {
|
||||
const assignments = await UserProjectRole.findAll({
|
||||
where: { user_id: userId },
|
||||
include: [
|
||||
{ model: Project, attributes: ["id", "name"] },
|
||||
{ model: Role, attributes: ["id", "name"] },
|
||||
],
|
||||
include: [ { model: Project, attributes: ["id", "name"] }, { model: Role, attributes: ["id", "name"] } ],
|
||||
});
|
||||
res.json(assignments);
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
} catch (error) { next(error); }
|
||||
});
|
||||
|
||||
router.post("/user-project-roles", async (req, res, next) => {
|
||||
router.post("/user-project-roles", requirePerm("users.manage"), async (req, res, next) => {
|
||||
const { userId, projectId, roleId } = req.body;
|
||||
if (!userId || !projectId || !roleId)
|
||||
return res
|
||||
.status(400)
|
||||
.json({ message: "userId, projectId, and roleId are required." });
|
||||
if (!userId || !projectId || !roleId) return res.status(400).json({ message: "userId, projectId, and roleId are required." });
|
||||
try {
|
||||
const [assignment, created] = await UserProjectRole.findOrCreate({
|
||||
where: { user_id: userId, project_id: projectId, role_id: roleId },
|
||||
defaults: { user_id: userId, project_id: projectId, role_id: roleId },
|
||||
});
|
||||
if (!created)
|
||||
return res
|
||||
.status(409)
|
||||
.json({ message: "This assignment already exists." });
|
||||
if (!created) return res.status(409).json({ message: "This assignment already exists." });
|
||||
res.status(201).json(assignment);
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
} catch (error) { next(error); }
|
||||
});
|
||||
|
||||
router.delete("/user-project-roles", async (req, res, next) => {
|
||||
router.delete("/user-project-roles", requirePerm("users.manage"), async (req, res, next) => {
|
||||
const { userId, projectId, roleId } = req.body;
|
||||
if (!userId || !projectId || !roleId)
|
||||
return res
|
||||
.status(400)
|
||||
.json({ message: "userId, projectId, and roleId are required." });
|
||||
if (!userId || !projectId || !roleId) return res.status(400).json({ message: "userId, projectId, and roleId are required." });
|
||||
try {
|
||||
const deletedCount = await UserProjectRole.destroy({
|
||||
where: { user_id: userId, project_id: projectId, role_id: roleId },
|
||||
});
|
||||
if (deletedCount === 0)
|
||||
return res.status(404).json({ message: "Assignment not found." });
|
||||
const deletedCount = await UserProjectRole.destroy({ where: { user_id: userId, project_id: projectId, role_id: roleId } });
|
||||
if (deletedCount === 0) return res.status(404).json({ message: 'Assignment not found.' });
|
||||
res.status(204).send();
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
} catch (error) { next(error); }
|
||||
});
|
||||
|
||||
export default router;
|
||||
export default router;
|
||||
205
backend/src/routes/users.js
Normal file → Executable file
205
backend/src/routes/users.js
Normal file → Executable file
@@ -1,136 +1,99 @@
|
||||
// File: backend/src/routes/users.js
|
||||
import { Router } from "express";
|
||||
import { User, Role } from "../db/sequelize.js";
|
||||
import { authJwt, permGuard } from "../middleware/index.js";
|
||||
import { hashPassword } from "../utils/passwords.js";
|
||||
import { Router } from 'express';
|
||||
import { User, Role } from '../db/sequelize.js';
|
||||
import { authJwt } from "../middleware/authJwt.js";
|
||||
import { loadPrincipalMw } from "../middleware/loadPrincipal.js"; // แก้ไข: import ให้ถูกต้อง
|
||||
import { requirePerm } from '../middleware/requirePerm.js';
|
||||
import { hashPassword } from '../utils/passwords.js';
|
||||
|
||||
const router = Router();
|
||||
|
||||
// Middleware สำหรับทุก route ในไฟล์นี้
|
||||
router.use(authJwt.verifyToken);
|
||||
// Middleware Chain ที่ถูกต้อง 100%
|
||||
router.use(authJwt(), loadPrincipalMw());
|
||||
|
||||
// GET /api/users - ดึงรายชื่อผู้ใช้ทั้งหมด
|
||||
router.get(
|
||||
"/",
|
||||
permGuard("manage_users"), // ตรวจสอบสิทธิ์
|
||||
async (req, res, next) => {
|
||||
// GET /api/users
|
||||
router.get('/', requirePerm('users.view'), async (req, res, next) => {
|
||||
try {
|
||||
const users = await User.findAll({
|
||||
attributes: { exclude: ["password_hash"] }, // **สำคัญมาก: ห้ามส่ง password hash ออกไป**
|
||||
include: [
|
||||
{
|
||||
model: Role,
|
||||
attributes: ["id", "name"],
|
||||
through: { attributes: [] }, // ไม่ต้องเอาข้อมูลจากตาราง join (UserRoles) มา
|
||||
},
|
||||
],
|
||||
order: [["username", "ASC"]],
|
||||
});
|
||||
res.json(users);
|
||||
const users = await User.findAll({
|
||||
attributes: { exclude: ['password_hash'] },
|
||||
include: [{ model: Role, attributes: ['id', 'name'], through: { attributes: [] } }],
|
||||
order: [['username', 'ASC']]
|
||||
});
|
||||
res.json(users);
|
||||
} catch (error) { next(error); }
|
||||
});
|
||||
|
||||
// POST /api/users
|
||||
router.post('/', requirePerm('users.manage'), async (req, res, next) => {
|
||||
const { username, email, password, first_name, last_name, is_active, roles } = req.body;
|
||||
if (!username || !email || !password) {
|
||||
return res.status(400).json({ message: 'Username, email, and password are required' });
|
||||
}
|
||||
try {
|
||||
const password_hash = await hashPassword(password);
|
||||
const newUser = await User.create({
|
||||
username, email, password_hash, first_name, last_name, is_active: is_active !== false,
|
||||
created_by: req.principal.user_id,
|
||||
updated_by: req.principal.user_id,
|
||||
org_id: req.principal.org_ids[0] || null,
|
||||
});
|
||||
|
||||
if (roles && roles.length > 0) {
|
||||
await newUser.setRoles(roles);
|
||||
}
|
||||
|
||||
const userWithRoles = await User.findByPk(newUser.id, {
|
||||
attributes: { exclude: ['password_hash'] },
|
||||
include: [{ model: Role, attributes: ['id', 'name'], through: { attributes: [] } }]
|
||||
});
|
||||
res.status(201).json(userWithRoles);
|
||||
} catch (error) {
|
||||
next(error);
|
||||
if (error.name === 'SequelizeUniqueConstraintError') {
|
||||
return res.status(409).json({ message: 'Username or email already exists.' });
|
||||
}
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// POST /api/users - สร้างผู้ใช้ใหม่
|
||||
router.post("/", permGuard("manage_users"), async (req, res, next) => {
|
||||
const { username, email, password, first_name, last_name, is_active, roles } =
|
||||
req.body;
|
||||
|
||||
if (!username || !email || !password) {
|
||||
return res
|
||||
.status(400)
|
||||
.json({ message: "Username, email, and password are required" });
|
||||
}
|
||||
|
||||
try {
|
||||
const password_hash = await hashPassword(password);
|
||||
const newUser = await User.create({
|
||||
username,
|
||||
email,
|
||||
password_hash,
|
||||
first_name,
|
||||
last_name,
|
||||
is_active: is_active !== false,
|
||||
});
|
||||
|
||||
if (roles && roles.length > 0) {
|
||||
await newUser.setRoles(roles);
|
||||
}
|
||||
|
||||
const userWithRoles = await User.findByPk(newUser.id, {
|
||||
attributes: { exclude: ["password_hash"] },
|
||||
include: [
|
||||
{
|
||||
model: Role,
|
||||
attributes: ["id", "name"],
|
||||
through: { attributes: [] },
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
res.status(201).json(userWithRoles);
|
||||
} catch (error) {
|
||||
if (error.name === "SequelizeUniqueConstraintError") {
|
||||
return res
|
||||
.status(409)
|
||||
.json({ message: "Username or email already exists." });
|
||||
}
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
// PUT /api/users/:id - อัปเดตข้อมูลผู้ใช้
|
||||
router.put("/:id", permGuard("manage_users"), async (req, res, next) => {
|
||||
const { id } = req.params;
|
||||
const { email, first_name, last_name, is_active, roles } = req.body;
|
||||
// PUT /api/users/:id
|
||||
router.put('/:id', requirePerm('users.manage'), async (req, res, next) => {
|
||||
const { id } = req.params;
|
||||
const { email, first_name, last_name, is_active, roles } = req.body;
|
||||
try {
|
||||
const user = await User.findByPk(id);
|
||||
if (!user) {
|
||||
return res.status(404).json({ message: 'User not found' });
|
||||
}
|
||||
user.email = email ?? user.email;
|
||||
user.first_name = first_name ?? user.first_name;
|
||||
user.last_name = last_name ?? user.last_name;
|
||||
user.is_active = is_active ?? user.is_active;
|
||||
user.updated_by = req.principal.user_id;
|
||||
await user.save();
|
||||
|
||||
try {
|
||||
const user = await User.findByPk(id);
|
||||
if (!user) {
|
||||
return res.status(404).json({ message: "User not found" });
|
||||
}
|
||||
|
||||
user.email = email ?? user.email;
|
||||
user.first_name = first_name ?? user.first_name;
|
||||
user.last_name = last_name ?? user.last_name;
|
||||
user.is_active = is_active ?? user.is_active;
|
||||
await user.save();
|
||||
|
||||
if (roles) {
|
||||
await user.setRoles(roles);
|
||||
}
|
||||
|
||||
const updatedUser = await User.findByPk(id, {
|
||||
attributes: { exclude: ["password_hash"] },
|
||||
include: [
|
||||
{
|
||||
model: Role,
|
||||
attributes: ["id", "name"],
|
||||
through: { attributes: [] },
|
||||
},
|
||||
],
|
||||
});
|
||||
res.json(updatedUser);
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
if (roles) {
|
||||
await user.setRoles(roles);
|
||||
}
|
||||
const updatedUser = await User.findByPk(id, {
|
||||
attributes: { exclude: ['password_hash'] },
|
||||
include: [{ model: Role, attributes: ['id', 'name'], through: { attributes: [] } }]
|
||||
});
|
||||
res.json(updatedUser);
|
||||
} catch (error) { next(error); }
|
||||
});
|
||||
|
||||
// DELETE /api/users/:id - ลบผู้ใช้ (Soft Delete)
|
||||
router.delete("/:id", permGuard("manage_users"), async (req, res, next) => {
|
||||
try {
|
||||
const user = await User.findByPk(req.params.id);
|
||||
if (!user) {
|
||||
return res.status(404).json({ message: "User not found" });
|
||||
}
|
||||
user.is_active = false; // Soft Delete
|
||||
await user.save();
|
||||
res.status(204).send();
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
// DELETE /api/users/:id
|
||||
router.delete('/:id', requirePerm('users.manage'), async (req, res, next) => {
|
||||
try {
|
||||
const user = await User.findByPk(req.params.id);
|
||||
if (!user) {
|
||||
return res.status(404).json({ message: 'User not found' });
|
||||
}
|
||||
user.is_active = false;
|
||||
user.updated_by = req.principal.user_id;
|
||||
await user.save();
|
||||
res.status(204).send();
|
||||
} catch (error) { next(error); }
|
||||
});
|
||||
|
||||
export default router;
|
||||
export default router;
|
||||
@@ -1,22 +0,0 @@
|
||||
{
|
||||
"$schema": "https://ui.shadcn.com/schema.json",
|
||||
"style": "new-york",
|
||||
"rsc": true,
|
||||
"tsx": false,
|
||||
"tailwind": {
|
||||
"config": "tailwind.config.js",
|
||||
"css": "app/globals.css",
|
||||
"baseColor": "neutral",
|
||||
"cssVariables": true,
|
||||
"prefix": ""
|
||||
},
|
||||
"iconLibrary": "lucide",
|
||||
"aliases": {
|
||||
"components": "@/components",
|
||||
"utils": "@/lib/utils",
|
||||
"ui": "@/components/ui",
|
||||
"lib": "@/lib",
|
||||
"hooks": "@/hooks"
|
||||
},
|
||||
"registries": {}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
<<<<<<< HEAD
|
||||
// frontend/lib/auth.js
|
||||
import { cookies } from "next/headers";
|
||||
|
||||
@@ -36,3 +37,43 @@ export async function getSession() {
|
||||
token,
|
||||
};
|
||||
}
|
||||
=======
|
||||
// frontend/lib/auth.js
|
||||
import { cookies } from "next/headers";
|
||||
|
||||
const COOKIE_NAME = "access_token";
|
||||
|
||||
/**
|
||||
* Server-side session fetcher (ใช้ใน Server Components/Layouts)
|
||||
* - อ่านคุกกี้แบบ async: await cookies()
|
||||
* - ถ้าไม่มี token → return null
|
||||
* - ถ้ามี → เรียก /api/auth/me ที่ backend เพื่อตรวจสอบ
|
||||
*/
|
||||
export async function getSession() {
|
||||
// ✅ ต้อง await
|
||||
const cookieStore = await cookies();
|
||||
const token = cookieStore.get(COOKIE_NAME)?.value;
|
||||
|
||||
if (!token) return null;
|
||||
|
||||
// เรียก backend ตรวจ session (ปรับ endpoint ให้ตรงของคุณ)
|
||||
const res = await fetch(`${process.env.NEXT_PUBLIC_API_BASE}/api/auth/me`, {
|
||||
// ส่งต่อคุกกี้ไป backend (เลือกอย่างใดอย่างหนึ่ง)
|
||||
// วิธี A: ส่ง header Cookie โดยตรง
|
||||
headers: { Cookie: `${COOKIE_NAME}=${token}` },
|
||||
// วิธี B: ถ้า proxy ผ่าน nginx ในโดเมนเดียวกัน ใช้ credentials รวมคุกกี้อัตโนมัติได้
|
||||
// credentials: "include",
|
||||
cache: "no-store",
|
||||
});
|
||||
|
||||
if (!res.ok) return null;
|
||||
|
||||
const data = await res.json();
|
||||
// คาดหวังโครงสร้าง { user, permissions } จาก backend
|
||||
return {
|
||||
user: data.user,
|
||||
permissions: data.permissions || [],
|
||||
token,
|
||||
};
|
||||
}
|
||||
>>>>>>> 71fc7eee (backend: Mod)
|
||||
|
||||
7509
frontend/package-lock.json
generated
Normal file
7509
frontend/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -7,12 +7,12 @@ services:
|
||||
user: "${UID:-1000}:${GID:-1000}"
|
||||
command: >
|
||||
sh -c "
|
||||
echo '📦 Installing dependencies...' &&
|
||||
echo '...installing dependencies...' &&
|
||||
npm install &&
|
||||
echo '🎨 Initializing shadcn/ui...' &&
|
||||
echo '...initiallizing shadcn/ui...' &&
|
||||
npx shadcn@latest init -y -d &&
|
||||
echo '📥 Adding components...' &&
|
||||
npx shadcn@latest add -y alert-dialog dialog checkbox scroll-area button label input card badge tabs progress dropdown-menu tooltip switch &&
|
||||
echo '...adding components...' &&
|
||||
npx shadcn@latest add -y alัert dialog checkbox scroll-area button label input card badge tabs progress dropdown-menu tooltip switch &&
|
||||
echo '✅ Done! Check components/ui/ directory'
|
||||
"
|
||||
|
||||
|
||||
BIN
mariadb/data/aria_log.00000001
Normal file
BIN
mariadb/data/aria_log.00000001
Normal file
Binary file not shown.
BIN
mariadb/data/aria_log_control
Normal file
BIN
mariadb/data/aria_log_control
Normal file
Binary file not shown.
BIN
n8n-postgres/base/16384/1247
Executable file
BIN
n8n-postgres/base/16384/1247
Executable file
Binary file not shown.
BIN
n8n-postgres/base/16384/1247_vm
Executable file
BIN
n8n-postgres/base/16384/1247_vm
Executable file
Binary file not shown.
BIN
n8n-postgres/base/16384/1249
Executable file
BIN
n8n-postgres/base/16384/1249
Executable file
Binary file not shown.
BIN
n8n-postgres/base/16384/1249_fsm
Executable file
BIN
n8n-postgres/base/16384/1249_fsm
Executable file
Binary file not shown.
BIN
n8n-postgres/base/16384/1249_vm
Executable file
BIN
n8n-postgres/base/16384/1249_vm
Executable file
Binary file not shown.
BIN
n8n-postgres/base/16384/1259
Executable file
BIN
n8n-postgres/base/16384/1259
Executable file
Binary file not shown.
BIN
n8n-postgres/base/16384/1259_vm
Executable file
BIN
n8n-postgres/base/16384/1259_vm
Executable file
Binary file not shown.
BIN
n8n-postgres/base/16384/2608
Executable file
BIN
n8n-postgres/base/16384/2608
Executable file
Binary file not shown.
BIN
n8n-postgres/base/16384/2608_vm
Executable file
BIN
n8n-postgres/base/16384/2608_vm
Executable file
Binary file not shown.
BIN
n8n-postgres/base/16384/2619
Executable file
BIN
n8n-postgres/base/16384/2619
Executable file
Binary file not shown.
BIN
n8n-postgres/base/16384/2619_fsm
Executable file
BIN
n8n-postgres/base/16384/2619_fsm
Executable file
Binary file not shown.
BIN
n8n-postgres/base/16384/2658
Executable file
BIN
n8n-postgres/base/16384/2658
Executable file
Binary file not shown.
BIN
n8n-postgres/base/16384/2658_fsm
Executable file
BIN
n8n-postgres/base/16384/2658_fsm
Executable file
Binary file not shown.
BIN
n8n-postgres/base/16384/2659
Executable file
BIN
n8n-postgres/base/16384/2659
Executable file
Binary file not shown.
BIN
n8n-postgres/base/16384/2659_fsm
Executable file
BIN
n8n-postgres/base/16384/2659_fsm
Executable file
Binary file not shown.
BIN
n8n-postgres/base/16384/2662
Executable file
BIN
n8n-postgres/base/16384/2662
Executable file
Binary file not shown.
BIN
n8n-postgres/base/16384/2663
Executable file
BIN
n8n-postgres/base/16384/2663
Executable file
Binary file not shown.
BIN
n8n-postgres/base/16384/2673
Executable file
BIN
n8n-postgres/base/16384/2673
Executable file
Binary file not shown.
BIN
n8n-postgres/base/16384/2673_fsm
Normal file
BIN
n8n-postgres/base/16384/2673_fsm
Normal file
Binary file not shown.
BIN
n8n-postgres/base/16384/2674
Executable file
BIN
n8n-postgres/base/16384/2674
Executable file
Binary file not shown.
BIN
n8n-postgres/base/16384/2696
Executable file
BIN
n8n-postgres/base/16384/2696
Executable file
Binary file not shown.
BIN
n8n-postgres/base/16384/2703
Executable file
BIN
n8n-postgres/base/16384/2703
Executable file
Binary file not shown.
BIN
n8n-postgres/base/16384/2704
Executable file
BIN
n8n-postgres/base/16384/2704
Executable file
Binary file not shown.
BIN
n8n-postgres/base/16384/2840
Executable file
BIN
n8n-postgres/base/16384/2840
Executable file
Binary file not shown.
BIN
n8n-postgres/base/16384/2841
Executable file
BIN
n8n-postgres/base/16384/2841
Executable file
Binary file not shown.
BIN
n8n-postgres/base/16384/3455
Executable file
BIN
n8n-postgres/base/16384/3455
Executable file
Binary file not shown.
BIN
n8n-postgres/base/16384/pg_internal.init
Normal file
BIN
n8n-postgres/base/16384/pg_internal.init
Normal file
Binary file not shown.
BIN
n8n-postgres/global/pg_control
Executable file
BIN
n8n-postgres/global/pg_control
Executable file
Binary file not shown.
BIN
n8n-postgres/global/pg_internal.init
Normal file
BIN
n8n-postgres/global/pg_internal.init
Normal file
Binary file not shown.
BIN
n8n-postgres/pg_wal/000000010000000000000004
Executable file
BIN
n8n-postgres/pg_wal/000000010000000000000004
Executable file
Binary file not shown.
BIN
n8n-postgres/pg_xact/0000
Executable file
BIN
n8n-postgres/pg_xact/0000
Executable file
Binary file not shown.
8
n8n-postgres/postmaster.pid
Normal file
8
n8n-postgres/postmaster.pid
Normal file
@@ -0,0 +1,8 @@
|
||||
1
|
||||
/var/lib/postgresql/data
|
||||
1759595341
|
||||
5432
|
||||
/var/run/postgresql
|
||||
*
|
||||
117512122 0
|
||||
ready
|
||||
BIN
npm/data/database.sqlite
Normal file
BIN
npm/data/database.sqlite
Normal file
Binary file not shown.
102
npm/data/nginx/proxy_host/5.conf
Normal file
102
npm/data/nginx/proxy_host/5.conf
Normal file
@@ -0,0 +1,102 @@
|
||||
# ------------------------------------------------------------
|
||||
# git.np-dms.work
|
||||
# ------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
map $scheme $hsts_header {
|
||||
https "max-age=63072000; preload";
|
||||
}
|
||||
|
||||
server {
|
||||
set $forward_scheme http;
|
||||
set $server "gitea";
|
||||
set $port 3000;
|
||||
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
|
||||
listen 443 ssl;
|
||||
listen [::]:443 ssl;
|
||||
|
||||
|
||||
server_name git.np-dms.work;
|
||||
|
||||
http2 on;
|
||||
|
||||
|
||||
# Let's Encrypt SSL
|
||||
include conf.d/include/letsencrypt-acme-challenge.conf;
|
||||
include conf.d/include/ssl-cache.conf;
|
||||
include conf.d/include/ssl-ciphers.conf;
|
||||
ssl_certificate /etc/letsencrypt/live/npm-10/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/npm-10/privkey.pem;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Block Exploits
|
||||
include conf.d/include/block-exploits.conf;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Force SSL
|
||||
include conf.d/include/force-ssl.conf;
|
||||
|
||||
|
||||
|
||||
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $http_connection;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
|
||||
access_log /data/logs/proxy-host-5_access.log proxy;
|
||||
error_log /data/logs/proxy-host-5_error.log warn;
|
||||
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header Authorization $http_authorization;
|
||||
|
||||
proxy_connect_timeout 30s;
|
||||
proxy_send_timeout 300s;
|
||||
proxy_read_timeout 300s;
|
||||
send_timeout 300s;
|
||||
client_max_body_size 512m;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
location / {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $http_connection;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
|
||||
# Proxy!
|
||||
include conf.d/include/proxy.conf;
|
||||
}
|
||||
|
||||
|
||||
# Custom
|
||||
include /data/nginx/custom/server_proxy[.]conf;
|
||||
}
|
||||
Reference in New Issue
Block a user