Update frontend login page.jsx และ backend
This commit is contained in:
@@ -1,15 +1,23 @@
|
||||
import { Router } from 'express';
|
||||
import { requireAuth } from '../middleware/auth.js';
|
||||
import { enrichPermissions } from '../middleware/permissions.js';
|
||||
import { requireRole } from '../middleware/rbac.js';
|
||||
import { requirePerm } from '../middleware/permGuard.js';
|
||||
import { sequelize } from '../db/sequelize.js';
|
||||
import RfaModel from '../db/models/RFA.js';
|
||||
import DrawingModel from '../db/models/Drawing.js';
|
||||
import RfaDrawMapModel from '../db/models/RfaDrawingMap.js';
|
||||
import CorrModel from '../db/models/Correspondence.js';
|
||||
import DocModel from '../db/models/Document.js';
|
||||
import CorrDocMapModel from '../db/models/CorrDocumentMap.js';
|
||||
// FILE: src/routes/maps.js
|
||||
// Maps routes
|
||||
// - Manage relationships between RFAs and Drawings, Correspondences and Documents
|
||||
// - Requires appropriate permissions via requirePerm middleware
|
||||
// - Uses project scope for RFA-Drawing maps and Correspondence-Document maps
|
||||
// - rfa:update for RFA-Drawing maps
|
||||
// - correspondence:update for Correspondence-Document maps
|
||||
|
||||
import { Router } from "express";
|
||||
import { requireAuth } from "../middleware/auth.js";
|
||||
import { enrichPermissions } from "../middleware/permissions.js";
|
||||
import { requireRole } from "../middleware/rbac.js";
|
||||
import { requirePerm } from "../middleware/permGuard.js";
|
||||
import { sequelize } from "../db/sequelize.js";
|
||||
import RfaModel from "../db/models/RFA.js";
|
||||
import DrawingModel from "../db/models/Drawing.js";
|
||||
import RfaDrawMapModel from "../db/models/RfaDrawingMap.js";
|
||||
import CorrModel from "../db/models/Correspondence.js";
|
||||
import DocModel from "../db/models/Document.js";
|
||||
import CorrDocMapModel from "../db/models/CorrDocumentMap.js";
|
||||
|
||||
const r = Router();
|
||||
const RFA = RfaModel(sequelize);
|
||||
@@ -22,62 +30,121 @@ const CorrDoc = CorrDocMapModel(sequelize);
|
||||
async function ensureRfaMembership(req, res) {
|
||||
const rfaId = Number(req.params.rfa_id);
|
||||
const row = await RFA.findByPk(rfaId);
|
||||
if (!row) { res.status(404).json({ error:'RFA not found' }); return false; }
|
||||
const roles = req.user?.roles || []; const isAdmin = roles.includes('Admin');
|
||||
if (!row) {
|
||||
res.status(404).json({ error: "RFA not found" });
|
||||
return false;
|
||||
}
|
||||
const roles = req.user?.roles || [];
|
||||
const isAdmin = roles.includes("Admin");
|
||||
if (isAdmin) return true;
|
||||
const { getUserProjectIds } = await import('../middleware/abac.js');
|
||||
const { getUserProjectIds } = await import("../middleware/abac.js");
|
||||
const memberProjects = await getUserProjectIds(req.user?.user_id);
|
||||
if (!memberProjects.includes(Number(row.project_id))) { res.status(403).json({ error:'Forbidden: not a project member' }); return false; }
|
||||
if (!memberProjects.includes(Number(row.project_id))) {
|
||||
res.status(403).json({ error: "Forbidden: not a project member" });
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
async function ensureCorrMembership(req, res) {
|
||||
const corrId = Number(req.params.corr_id);
|
||||
const row = await Corr.findByPk(corrId);
|
||||
if (!row) { res.status(404).json({ error:'Correspondence not found' }); return false; }
|
||||
const roles = req.user?.roles || []; const isAdmin = roles.includes('Admin');
|
||||
if (!row) {
|
||||
res.status(404).json({ error: "Correspondence not found" });
|
||||
return false;
|
||||
}
|
||||
const roles = req.user?.roles || [];
|
||||
const isAdmin = roles.includes("Admin");
|
||||
if (isAdmin) return true;
|
||||
const { getUserProjectIds } = await import('../middleware/abac.js');
|
||||
const { getUserProjectIds } = await import("../middleware/abac.js");
|
||||
const memberProjects = await getUserProjectIds(req.user?.user_id);
|
||||
if (!memberProjects.includes(Number(row.project_id))) { res.status(403).json({ error:'Forbidden: not a project member' }); return false; }
|
||||
if (!memberProjects.includes(Number(row.project_id))) {
|
||||
res.status(403).json({ error: "Forbidden: not a project member" });
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// RFA <-> Drawing
|
||||
r.get('/maps/rfa/:rfa_id/drawings', requireAuth, async (req, res) => {
|
||||
const rows = await RfaDraw.findAll({ where: { rfa_id: Number(req.params.rfa_id) } });
|
||||
r.get("/maps/rfa/:rfa_id/drawings", requireAuth, async (req, res) => {
|
||||
const rows = await RfaDraw.findAll({
|
||||
where: { rfa_id: Number(req.params.rfa_id) },
|
||||
});
|
||||
res.json(rows);
|
||||
});
|
||||
r.post('/maps/rfa/:rfa_id/drawings/:drawing_id', requireAuth, enrichPermissions(), requirePerm('rfa:update'), async (req, res) => {
|
||||
if (!(await ensureRfaMembership(req, res))) return;
|
||||
const { rfa_id, drawing_id } = { rfa_id: Number(req.params.rfa_id), drawing_id: Number(req.params.drawing_id) };
|
||||
await RfaDraw.create({ rfa_id, drawing_id });
|
||||
res.status(201).json({ ok: true });
|
||||
});
|
||||
r.delete('/maps/rfa/:rfa_id/drawings/:drawing_id', requireAuth, enrichPermissions(), requirePerm('rfa:update'), async (req, res) => {
|
||||
if (!(await ensureRfaMembership(req, res))) return;
|
||||
const { rfa_id, drawing_id } = { rfa_id: Number(req.params.rfa_id), drawing_id: Number(req.params.drawing_id) };
|
||||
const count = await RfaDraw.destroy({ where: { rfa_id, drawing_id } });
|
||||
res.json({ ok: count > 0 });
|
||||
});
|
||||
r.post(
|
||||
"/maps/rfa/:rfa_id/drawings/:drawing_id",
|
||||
requireAuth,
|
||||
enrichPermissions(),
|
||||
requirePerm("rfa:update"),
|
||||
async (req, res) => {
|
||||
if (!(await ensureRfaMembership(req, res))) return;
|
||||
const { rfa_id, drawing_id } = {
|
||||
rfa_id: Number(req.params.rfa_id),
|
||||
drawing_id: Number(req.params.drawing_id),
|
||||
};
|
||||
await RfaDraw.create({ rfa_id, drawing_id });
|
||||
res.status(201).json({ ok: true });
|
||||
}
|
||||
);
|
||||
r.delete(
|
||||
"/maps/rfa/:rfa_id/drawings/:drawing_id",
|
||||
requireAuth,
|
||||
enrichPermissions(),
|
||||
requirePerm("rfa:update"),
|
||||
async (req, res) => {
|
||||
if (!(await ensureRfaMembership(req, res))) return;
|
||||
const { rfa_id, drawing_id } = {
|
||||
rfa_id: Number(req.params.rfa_id),
|
||||
drawing_id: Number(req.params.drawing_id),
|
||||
};
|
||||
const count = await RfaDraw.destroy({ where: { rfa_id, drawing_id } });
|
||||
res.json({ ok: count > 0 });
|
||||
}
|
||||
);
|
||||
|
||||
// Correspondence <-> Document
|
||||
r.get('/maps/correspondence/:corr_id/documents', requireAuth, async (req, res) => {
|
||||
const rows = await CorrDoc.findAll({ where: { correspondence_id: Number(req.params.corr_id) } });
|
||||
res.json(rows);
|
||||
});
|
||||
r.post('/maps/correspondence/:corr_id/documents/:doc_id', requireAuth, enrichPermissions(), requirePerm('correspondence:update'), async (req, res) => {
|
||||
if (!(await ensureCorrMembership(req, res))) return;
|
||||
const { corr_id, doc_id } = { corr_id: Number(req.params.corr_id), doc_id: Number(req.params.doc_id) };
|
||||
await CorrDoc.create({ correspondence_id: corr_id, document_id: doc_id });
|
||||
res.status(201).json({ ok: true });
|
||||
});
|
||||
r.delete('/maps/correspondence/:corr_id/documents/:doc_id', requireAuth, enrichPermissions(), requirePerm('correspondence:update'), async (req, res) => {
|
||||
if (!(await ensureCorrMembership(req, res))) return;
|
||||
const { corr_id, doc_id } = { corr_id: Number(req.params.corr_id), doc_id: Number(req.params.doc_id) };
|
||||
const count = await CorrDoc.destroy({ where: { correspondence_id: corr_id, document_id: doc_id } });
|
||||
res.json({ ok: count > 0 });
|
||||
});
|
||||
r.get(
|
||||
"/maps/correspondence/:corr_id/documents",
|
||||
requireAuth,
|
||||
async (req, res) => {
|
||||
const rows = await CorrDoc.findAll({
|
||||
where: { correspondence_id: Number(req.params.corr_id) },
|
||||
});
|
||||
res.json(rows);
|
||||
}
|
||||
);
|
||||
r.post(
|
||||
"/maps/correspondence/:corr_id/documents/:doc_id",
|
||||
requireAuth,
|
||||
enrichPermissions(),
|
||||
requirePerm("correspondence:update"),
|
||||
async (req, res) => {
|
||||
if (!(await ensureCorrMembership(req, res))) return;
|
||||
const { corr_id, doc_id } = {
|
||||
corr_id: Number(req.params.corr_id),
|
||||
doc_id: Number(req.params.doc_id),
|
||||
};
|
||||
await CorrDoc.create({ correspondence_id: corr_id, document_id: doc_id });
|
||||
res.status(201).json({ ok: true });
|
||||
}
|
||||
);
|
||||
r.delete(
|
||||
"/maps/correspondence/:corr_id/documents/:doc_id",
|
||||
requireAuth,
|
||||
enrichPermissions(),
|
||||
requirePerm("correspondence:update"),
|
||||
async (req, res) => {
|
||||
if (!(await ensureCorrMembership(req, res))) return;
|
||||
const { corr_id, doc_id } = {
|
||||
corr_id: Number(req.params.corr_id),
|
||||
doc_id: Number(req.params.doc_id),
|
||||
};
|
||||
const count = await CorrDoc.destroy({
|
||||
where: { correspondence_id: corr_id, document_id: doc_id },
|
||||
});
|
||||
res.json({ ok: count > 0 });
|
||||
}
|
||||
);
|
||||
|
||||
export default r;
|
||||
|
||||
Reference in New Issue
Block a user