폴더단위 권한 제어 기능 추가

This commit is contained in:
koj729
2026-06-15 13:51:06 +09:00
parent 4e33c9a02a
commit d13c414d7f
15 changed files with 1324 additions and 129 deletions

View File

@@ -1,11 +1,18 @@
/**
* [변경 이력 (Auto-Generated by AI)]
* - 수정일시: 2026-06-15 11:40:00
* - 수정원인: 폴더별 권한 관리 트리 노드의 data_permission 기준 정렬 요구사항 반영
* - 수정내용: getFolderPermissions API의 foldersQuery에 data_permission 컬럼을 조회하도록 SELECT절 추가
*/
const pool = require("../../db/pool.js");
const crypto = require("crypto");
const env = process.env.NODE_ENV;
const tbProject = env === 'production' ? 'tb_project' : '_test_tb_project';
const tbData = env === 'production' ? 'tb_data' : '_test_tb_data';
const tbLog = 'tb_log';
const tbLog = env === 'production' ? 'tb_log' : '_test_tb_log';
const tbPermission = env === 'production' ? 'tb_permission' : '_test_tb_permission';
const tbFolderPermission = env === 'production' ? 'tb_folder_permission' : '_test_tb_folder_permission';
// 감사 로그(Audit Log) 삽입 헬퍼 함수 (메인 트랜잭션에 영향을 주지 않기 위해 pool.query 사용)
@@ -578,34 +585,39 @@ exports.deleteUser = async (req, res) => {
}
};
// 5. 감사 로그 조회 (Audit Logs)
// 5. 활동 로그 조회 (Activity Logs)
exports.getAuditLogs = async (req, res) => {
const { user_id, activity } = req.query;
const { user_id, activity, project_nm } = req.query;
const client = await pool.connect();
try {
let query = `
SELECT log_id, log_date as clean_date, project_id, user_id, user_ip, activity as clean_path, path_arr as criteria_info
FROM ver4.${tbLog}
SELECT l.log_id, l.log_date as clean_date, l.project_id, p.project_nm, l.user_id, l.user_ip, l.activity as clean_path, l.path_arr as criteria_info
FROM ver4.${tbLog} l
LEFT JOIN ver4.${tbProject} p ON l.project_id = p.project_id
WHERE 1=1
`;
const params = [];
let paramIndex = 1;
if (user_id) {
query += ` AND user_id ILIKE $${paramIndex++}`;
query += ` AND l.user_id ILIKE $${paramIndex++}`;
params.push(`%${user_id}%`);
}
if (project_nm) {
query += ` AND (p.project_nm ILIKE $${paramIndex++} OR l.project_id ILIKE $${paramIndex - 1})`;
params.push(`%${project_nm}%`);
}
if (activity && activity !== 'all') {
query += ` AND activity = $${paramIndex++}`;
params.push(activity);
query += ` AND l.activity ILIKE $${paramIndex++}`;
params.push(`%${activity}%`);
}
query += ` ORDER BY log_id DESC LIMIT 100;`;
query += ` ORDER BY l.log_id DESC LIMIT 100;`;
const result = await client.query(query, params);
res.status(200).json(result.rows);
} catch (err) {
console.error("getAuditLogs Error:", err);
res.status(500).json({ error: "감사 로그 조회 실패" });
res.status(500).json({ error: "활동 로그 조회 실패" });
} finally {
client.release();
}
@@ -902,3 +914,118 @@ exports.deleteCodeDetail = async (req, res) => {
client.release();
}
};
// 2-1. Folder-Level Permissions
exports.getFolderPermissions = async (req, res) => {
const { projectId } = req.params;
const client = await pool.connect();
try {
// 1. Fetch folders (depth <= 3)
const foldersQuery = `
SELECT data_id, path1, path2, path3, data_depth, is_folder, data_permission
FROM ver4.${tbData}
WHERE project_id = $1 AND is_folder = true AND is_removed = false AND data_depth <= 3
ORDER BY path1, path2, path3;
`;
const foldersRes = await client.query(foldersQuery, [projectId]);
// 2. Fetch current folder permissions
const folderPermsQuery = `
SELECT fp.folder_permission_id, fp.folder_path_key, fp.user_id, fp.lev, u.user_nm
FROM ver4.${tbFolderPermission} fp
JOIN ver4.tb_user u ON fp.user_id = u.user_id
WHERE fp.project_id = $1;
`;
const folderPermsRes = await client.query(folderPermsQuery, [projectId]);
// 3. Fetch project users
const usersQuery = `
SELECT pm.user_id, u.user_nm, u.company, u.dept, u.position, pm.lev as project_lev
FROM ver4.${tbPermission} pm
JOIN ver4.tb_user u ON pm.user_id = u.user_id
WHERE pm.project_id = $1
ORDER BY u.user_nm ASC;
`;
const usersRes = await client.query(usersQuery, [projectId]);
res.status(200).json({
folders: foldersRes.rows,
folderPermissions: folderPermsRes.rows,
users: usersRes.rows
});
} catch (err) {
console.error("getFolderPermissions Error:", err);
res.status(500).json({ error: "폴더 권한 정보 조회 실패" });
} finally {
client.release();
}
};
exports.assignFolderPermissions = async (req, res) => {
const { project_id, folder_path_key, user_id, lev } = req.body;
if (!project_id || !folder_path_key || !user_id || lev === undefined) {
return res.status(400).json({ error: "필수 파라미터가 누락되었습니다." });
}
const client = await pool.connect();
try {
const query = `
INSERT INTO ver4.${tbFolderPermission} (project_id, folder_path_key, user_id, lev, mod_date)
VALUES ($1, $2, $3, $4, CURRENT_TIMESTAMP)
ON CONFLICT (project_id, folder_path_key, user_id)
DO UPDATE SET lev = EXCLUDED.lev, mod_date = CURRENT_TIMESTAMP
RETURNING *;
`;
const result = await client.query(query, [project_id, folder_path_key, user_id, lev]);
const userIp = req.headers['cf-connecting-ip'] || req.ip || req.headers['x-forwarded-for'] || req.connection?.remoteAddress;
await insertAuditLog(project_id, 'assignFolderPermission', req.user?.user_id, userIp, [
`Folder path: ${folder_path_key}`,
`Assigned user_id: ${user_id}`,
`Folder level assigned: ${lev}`
]);
res.status(200).json({
message: "폴더 권한이 성공적으로 부여되었습니다.",
data: result.rows[0]
});
} catch (err) {
console.error("assignFolderPermissions Error:", err);
res.status(500).json({ error: "폴더 권한 부여 실패" });
} finally {
client.release();
}
};
exports.removeFolderPermission = async (req, res) => {
const { project_id, folder_path_key, user_id } = req.body;
if (!project_id || !folder_path_key || !user_id) {
return res.status(400).json({ error: "필수 파라미터가 누락되었습니다." });
}
const client = await pool.connect();
try {
const query = `
DELETE FROM ver4.${tbFolderPermission}
WHERE project_id = $1 AND folder_path_key = $2 AND user_id = $3
RETURNING *;
`;
const result = await client.query(query, [project_id, folder_path_key, user_id]);
if (result.rows.length === 0) {
return res.status(404).json({ error: "대상을 찾을 수 없습니다." });
}
const userIp = req.headers['cf-connecting-ip'] || req.ip || req.headers['x-forwarded-for'] || req.connection?.remoteAddress;
await insertAuditLog(project_id, 'removeFolderPermission', req.user?.user_id, userIp, [
`Folder path: ${folder_path_key}`,
`Removed user_id: ${user_id}`
]);
res.status(200).json({ message: "폴더 권한이 제거되었으며 상속 상태로 초기화되었습니다." });
} catch (err) {
console.error("removeFolderPermission Error:", err);
res.status(500).json({ error: "폴더 권한 삭제 실패" });
} finally {
client.release();
}
};