05.1 ปรบปรง backend ทงหมด และ frontend/login
This commit is contained in:
		| @@ -1,50 +1,49 @@ | ||||
| // FILE: src/routes/projects.js | ||||
| // 03.2 6) เพิ่ม routes/projects.js (ใหม่) | ||||
| // - ใช้ร่วมกับ requirePerm() และ buildScopeWhere() | ||||
| // - สำหรับจัดการ projects (ดู/เพิ่ม/แก้ไข/ลบ) ตามสิทธิ์ของผู้ใช้ | ||||
| // Projects routes | ||||
| // - CRUD operations for projects | ||||
| // - Requires appropriate permissions via requirePerm middleware | ||||
| // - Uses org/project scope for all permissions | ||||
| // - project:read, project:create, project:update, project:delete | ||||
| // - Project fields: project_id (PK), org_id (FK), project_code, project_name | ||||
| // - project_code is unique | ||||
| // - Basic validation: org_id, project_code, project_name required for create | ||||
| // FILE: backend/src/routes/projects.js | ||||
|  | ||||
| import { Router } from "express"; | ||||
| import sql from "../db/index.js"; | ||||
| import { requirePerm } from "../middleware/requirePerm.js"; | ||||
| import { buildScopeWhere } from "../utils/scope.js"; | ||||
|  | ||||
| const r = Router(); | ||||
|  | ||||
| // LIST – จำกัดตาม org/project scope ของผู้ใช้ | ||||
| // LIST — ORG scope | ||||
| r.get( | ||||
|   "/", | ||||
|   requirePerm("project.read", { scope: "global" }), | ||||
|   requirePerm("projects.view", { orgParam: "org_id" }), | ||||
|   async (req, res) => { | ||||
|     const { where, params } = buildScopeWhere(req.principal, { | ||||
|       tableAlias: "p", | ||||
|       orgColumn: "p.org_id", | ||||
|       projectColumn: "p.project_id", | ||||
|       permCode: "project.read", | ||||
|       preferProject: true, | ||||
|     }); | ||||
|     const p = req.principal; | ||||
|     const { org_id } = req.query; | ||||
|     const params = []; | ||||
|     const cond = []; | ||||
|  | ||||
|     if (!p.is_superadmin) { | ||||
|       if (org_id) { | ||||
|         if (!p.inOrg(Number(org_id))) | ||||
|           return res.status(403).json({ error: "FORBIDDEN_ORG" }); | ||||
|         cond.push("p.org_id=?"); | ||||
|         params.push(Number(org_id)); | ||||
|       } else if (p.org_ids?.length) { | ||||
|         cond.push(`p.org_id IN (${p.org_ids.map(() => "?").join(",")})`); | ||||
|         params.push(...p.org_ids); | ||||
|       } | ||||
|     } else if (org_id) { | ||||
|       cond.push("p.org_id=?"); | ||||
|       params.push(Number(org_id)); | ||||
|     } | ||||
|  | ||||
|     const where = cond.length ? `WHERE ${cond.join(" AND ")}` : ""; | ||||
|     const [rows] = await sql.query( | ||||
|       `SELECT p.* FROM projects p WHERE ${where}`, | ||||
|       `SELECT p.* FROM projects p ${where} ORDER BY p.project_name`, | ||||
|       params | ||||
|     ); | ||||
|     res.json(rows); | ||||
|   } | ||||
| ); | ||||
|  | ||||
| // GET | ||||
| // GET — PROJECT scope | ||||
| r.get( | ||||
|   "/:id", | ||||
|   requirePerm("project.read", { | ||||
|     scope: "project", | ||||
|     getProjectId: async (req) => Number(req.params.id), | ||||
|   }), | ||||
|   requirePerm("projects.view", { orgParam: "org_id" }), | ||||
|   async (req, res) => { | ||||
|     const id = Number(req.params.id); | ||||
|     const [[row]] = await sql.query( | ||||
| @@ -52,54 +51,71 @@ r.get( | ||||
|       [id] | ||||
|     ); | ||||
|     if (!row) return res.status(404).json({ error: "Not found" }); | ||||
|     const p = req.principal; | ||||
|     if (!p.is_superadmin && !p.inOrg(row.org_id)) | ||||
|       return res.status(403).json({ error: "FORBIDDEN_ORG" }); | ||||
|     res.json(row); | ||||
|   } | ||||
| ); | ||||
|  | ||||
| // CREATE | ||||
| // CREATE — ORG scope | ||||
| r.post( | ||||
|   "/", | ||||
|   requirePerm("project.create", { | ||||
|     scope: "org", | ||||
|     getOrgId: async (req) => req.body?.org_id ?? null, | ||||
|   }), | ||||
|   requirePerm("projects.manage", { orgParam: "org_id" }), | ||||
|   async (req, res) => { | ||||
|     const { org_id, project_code, project_name } = req.body; | ||||
|     const { org_id, project_code, project_name } = req.body || {}; | ||||
|     if (!org_id || !project_code || !project_name) { | ||||
|       return res | ||||
|         .status(400) | ||||
|         .json({ error: "org_id, project_code, project_name required" }); | ||||
|     } | ||||
|     const [rs] = await sql.query( | ||||
|       "INSERT INTO projects (org_id, project_code, project_name) VALUES (?,?,?)", | ||||
|       [org_id, project_code, project_name] | ||||
|       "INSERT INTO projects (org_id, project_code, project_name, created_by) VALUES (?,?,?,?)", | ||||
|       [Number(org_id), project_code, project_name, req.principal.user_id] | ||||
|     ); | ||||
|     res.json({ project_id: rs.insertId }); | ||||
|     res.status(201).json({ project_id: rs.insertId }); | ||||
|   } | ||||
| ); | ||||
|  | ||||
| // UPDATE | ||||
| // UPDATE — ORG scope | ||||
| r.put( | ||||
|   "/:id", | ||||
|   requirePerm("project.update", { | ||||
|     scope: "project", | ||||
|     getProjectId: async (req) => Number(req.params.id), | ||||
|   }), | ||||
|   requirePerm("projects.manage", { orgParam: "org_id" }), | ||||
|   async (req, res) => { | ||||
|     const { project_name } = req.body; | ||||
|     const id = Number(req.params.id); | ||||
|     await sql.query("UPDATE projects SET project_name=? WHERE project_id=?", [ | ||||
|       project_name, | ||||
|       id, | ||||
|     ]); | ||||
|     const [[row]] = await sql.query( | ||||
|       "SELECT * FROM projects WHERE project_id=?", | ||||
|       [id] | ||||
|     ); | ||||
|     if (!row) return res.status(404).json({ error: "Not found" }); | ||||
|     const p = req.principal; | ||||
|     if (!p.is_superadmin && !p.inOrg(row.org_id)) | ||||
|       return res.status(403).json({ error: "FORBIDDEN_ORG" }); | ||||
|  | ||||
|     const { project_name } = req.body || {}; | ||||
|     await sql.query( | ||||
|       "UPDATE projects SET project_name=?, updated_by=? WHERE project_id=?", | ||||
|       [project_name ?? row.project_name, req.principal.user_id, id] | ||||
|     ); | ||||
|     res.json({ ok: 1 }); | ||||
|   } | ||||
| ); | ||||
|  | ||||
| // DELETE | ||||
| // DELETE — ORG scope | ||||
| r.delete( | ||||
|   "/:id", | ||||
|   requirePerm("project.delete", { | ||||
|     scope: "project", | ||||
|     getProjectId: async (req) => Number(req.params.id), | ||||
|   }), | ||||
|   requirePerm("projects.manage", { orgParam: "org_id" }), | ||||
|   async (req, res) => { | ||||
|     const id = Number(req.params.id); | ||||
|     const [[row]] = await sql.query( | ||||
|       "SELECT * FROM projects WHERE project_id=?", | ||||
|       [id] | ||||
|     ); | ||||
|     if (!row) return res.status(404).json({ error: "Not found" }); | ||||
|     const p = req.principal; | ||||
|     if (!p.is_superadmin && !p.inOrg(row.org_id)) | ||||
|       return res.status(403).json({ error: "FORBIDDEN_ORG" }); | ||||
|  | ||||
|     await sql.query("DELETE FROM projects WHERE project_id=?", [id]); | ||||
|     res.json({ ok: 1 }); | ||||
|   } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 admin
					admin