05.1 ปรบปรง backend ทงหมด และ frontend/login
This commit is contained in:
		| @@ -1,17 +1,4 @@ | ||||
| // FILE: src/db/index.js (ESM) | ||||
| // Database connection and query utility | ||||
| // - Uses mysql2/promise for connection pooling and async/await | ||||
| // - Exports a query function for executing SQL with parameters | ||||
| // - Connection settings are read from environment variables with defaults | ||||
| // - Uses named placeholders for query parameters | ||||
| // - Dates are handled as strings in UTC timezone to avoid timezone issues | ||||
| // - Connection pool is configured to handle multiple concurrent requests | ||||
| // ============================================================= | ||||
| // Load environment variables from .env file if present | ||||
| // (uncomment the next line if using dotenv) | ||||
| // import dotenv from 'dotenv'; dotenv.config(); | ||||
| // (Make sure to install dotenv package if using this line) | ||||
|  | ||||
| // FILE: backend/src/db/index.js (ESM) | ||||
| import mysql from "mysql2/promise"; | ||||
|  | ||||
| const { | ||||
| @@ -30,21 +17,23 @@ const pool = mysql.createPool({ | ||||
|   password: DB_PASSWORD, | ||||
|   database: DB_NAME, | ||||
|   connectionLimit: Number(DB_CONN_LIMIT), | ||||
|   waitForConnections: true, // Recommended for handling connection spikes | ||||
|   waitForConnections: true, | ||||
|   namedPlaceholders: true, | ||||
|   dateStrings: true, // Keep dates as strings | ||||
|   timezone: "Z", // Store and retrieve dates in UTC | ||||
|   dateStrings: true, // คงวันที่เป็น string | ||||
|   timezone: "Z", // ใช้ UTC | ||||
| }); | ||||
|  | ||||
| /** | ||||
|  * Executes a SQL query with parameters. | ||||
|  * @param {string} sql The SQL query string. | ||||
|  * @param {object} [params={}] The parameters to bind to the query. | ||||
|  * @returns {Promise<any[]>} A promise that resolves to an array of rows. | ||||
|  * เรียก Stored Procedure แบบง่าย | ||||
|  * @param {string} procName ชื่อโปรซีเยอร์ เช่น "sp_rfa_create_with_items" | ||||
|  * @param {Array<any>} params ลำดับพารามิเตอร์ | ||||
|  * @returns {Promise<any>} rows จาก CALL | ||||
|  */ | ||||
| export async function query(sql, params = {}) { | ||||
|   const [rows] = await pool.execute(sql, params); | ||||
| export async function callProc(procName, params = []) { | ||||
|   const placeholders = params.map(() => "?").join(","); | ||||
|   const sql = `CALL ${procName}(${placeholders})`; | ||||
|   const [rows] = await pool.query(sql, params); | ||||
|   return rows; | ||||
| } | ||||
|  | ||||
| export default pool; | ||||
| export default pool; // ใช้ sql.query(...) ได้ตามที่ routes เรียกอยู่ | ||||
|   | ||||
| @@ -1,10 +1,7 @@ | ||||
| // FILE: src/db/sequelize.js | ||||
| // Sequelize initialization and model definitions | ||||
| // - Configured via config.js | ||||
| // - Defines User, Role, Permission, UserRole, RolePermission models | ||||
| // - Sets up associations between models | ||||
| // - Exports sequelize instance and models for use in other modules | ||||
|  | ||||
| // FILE: backend/src/db/sequelize.js | ||||
| // “lazy-load” ตาม env ปลอดภัยกว่า และยังคง dbReady() ให้เรียกทดสอบได้ | ||||
| // ใช้ได้เมื่อจำเป็น (เช่น งาน admin tool เฉพาะกิจ) | ||||
| // ตั้ง ENABLE_SEQUELIZE=1 เพื่อเปิดใช้ Model loader; ไม่งั้นจะเป็นโหมดเบา ๆ | ||||
| import { Sequelize } from "sequelize"; | ||||
| import { config } from "../config.js"; | ||||
|  | ||||
| @@ -18,49 +15,57 @@ export const sequelize = new Sequelize( | ||||
|     dialect: "mariadb", | ||||
|     logging: false, | ||||
|     dialectOptions: { timezone: "Z" }, | ||||
|     define: { | ||||
|       freezeTableName: true, | ||||
|       underscored: false, | ||||
|       timestamps: false, | ||||
|     }, | ||||
|     define: { freezeTableName: true, underscored: false, timestamps: false }, | ||||
|     pool: { max: 10, min: 0, idle: 10000 }, | ||||
|   } | ||||
| ); | ||||
|  | ||||
| import UserModel from "./models/User.js"; | ||||
| import RoleModel from "./models/Role.js"; | ||||
| import PermissionModel from "./models/Permission.js"; | ||||
| import UserRoleModel from "./models/UserRole.js"; | ||||
| import RolePermissionModel from "./models/RolePermission.js"; | ||||
| export let User = null; | ||||
| export let Role = null; | ||||
| export let Permission = null; | ||||
| export let UserRole = null; | ||||
| export let RolePermission = null; | ||||
|  | ||||
| export const User = UserModel(sequelize); | ||||
| export const Role = RoleModel(sequelize); | ||||
| export const Permission = PermissionModel(sequelize); | ||||
| export const UserRole = UserRoleModel(sequelize); | ||||
| export const RolePermission = RolePermissionModel(sequelize); | ||||
| if (process.env.ENABLE_SEQUELIZE === "1") { | ||||
|   // โหลดโมเดลแบบ on-demand เพื่อลดความเสี่ยง runtime หากไฟล์โมเดลไม่มี | ||||
|   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); | ||||
|  | ||||
| User.belongsToMany(Role, { | ||||
|   through: UserRole, | ||||
|   foreignKey: "user_id", | ||||
|   otherKey: "role_id", | ||||
| }); | ||||
| Role.belongsToMany(User, { | ||||
|   through: UserRole, | ||||
|   foreignKey: "role_id", | ||||
|   otherKey: "user_id", | ||||
| }); | ||||
|   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); | ||||
|  | ||||
| Role.belongsToMany(Permission, { | ||||
|   through: RolePermission, | ||||
|   foreignKey: "role_id", | ||||
|   otherKey: "permission_id", | ||||
| }); | ||||
| Permission.belongsToMany(Role, { | ||||
|   through: RolePermission, | ||||
|   foreignKey: "permission_id", | ||||
|   otherKey: "role_id", | ||||
| }); | ||||
|   if (User && Role && Permission && UserRole && RolePermission) { | ||||
|     User.belongsToMany(Role, { | ||||
|       through: UserRole, | ||||
|       foreignKey: "user_id", | ||||
|       otherKey: "role_id", | ||||
|     }); | ||||
|     Role.belongsToMany(User, { | ||||
|       through: UserRole, | ||||
|       foreignKey: "role_id", | ||||
|       otherKey: "user_id", | ||||
|     }); | ||||
|  | ||||
|     Role.belongsToMany(Permission, { | ||||
|       through: RolePermission, | ||||
|       foreignKey: "role_id", | ||||
|       otherKey: "permission_id", | ||||
|     }); | ||||
|     Permission.belongsToMany(Role, { | ||||
|       through: RolePermission, | ||||
|       foreignKey: "permission_id", | ||||
|       otherKey: "role_id", | ||||
|     }); | ||||
|   } | ||||
| } | ||||
|  | ||||
| export async function dbReady() { | ||||
|   // โหมดเบา ๆ: แค่ทดสอบเชื่อมต่อ | ||||
|   await sequelize.authenticate(); | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 admin
					admin