초기 PM 소스 전체 업로드
This commit is contained in:
904
controllers/admin/adminController.js
Normal file
904
controllers/admin/adminController.js
Normal file
@@ -0,0 +1,904 @@
|
||||
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 tbPermission = env === 'production' ? 'tb_permission' : '_test_tb_permission';
|
||||
|
||||
|
||||
// 감사 로그(Audit Log) 삽입 헬퍼 함수 (메인 트랜잭션에 영향을 주지 않기 위해 pool.query 사용)
|
||||
async function insertAuditLog(projectId, activity, userId, userIp, detailsArray) {
|
||||
try {
|
||||
let targetProjectId = projectId;
|
||||
if (targetProjectId === 'SYSTEM' || !targetProjectId) {
|
||||
targetProjectId = null;
|
||||
} else {
|
||||
// 실제로 존재하는 프로젝트인지 더블 체크 (FK 에러 방지)
|
||||
const checkRes = await pool.query(`SELECT 1 FROM ver4.${tbProject} WHERE project_id = $1`, [targetProjectId]);
|
||||
if (checkRes.rows.length === 0) {
|
||||
targetProjectId = null;
|
||||
}
|
||||
}
|
||||
|
||||
const query = `
|
||||
INSERT INTO ver4.${tbLog} (project_id, activity, user_id, user_ip, log_date, path_arr)
|
||||
VALUES ($1, $2, $3, $4, CURRENT_TIMESTAMP, $5);
|
||||
`;
|
||||
await pool.query(query, [
|
||||
targetProjectId,
|
||||
activity,
|
||||
userId || 'unknown_admin',
|
||||
userIp || '0.0.0.0',
|
||||
detailsArray || []
|
||||
]);
|
||||
} catch (logErr) {
|
||||
console.error("🚨 [insertAuditLog] Audit log insert failed:", logErr);
|
||||
}
|
||||
}
|
||||
|
||||
// 1. 프로젝트 관리 (Projects)
|
||||
exports.getProjects = async (req, res) => {
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
const query = `
|
||||
SELECT
|
||||
p.*,
|
||||
cd.code_nm as category_nm,
|
||||
COALESCE(d.total_size, 0)::BIGINT as used_bytes,
|
||||
COALESCE(d.file_count, 0)::INTEGER as file_count
|
||||
FROM ver4.${tbProject} p
|
||||
LEFT JOIN ver4.code_detail cd ON cd.main_code = 'PROJECT_CATEGORY' AND p.category = cd.sub_code
|
||||
LEFT JOIN (
|
||||
SELECT project_id, SUM(COALESCE(data_size, 0)) as total_size, COUNT(*) as file_count
|
||||
FROM ver4.${tbData}
|
||||
WHERE is_folder = false AND (is_removed = false OR is_removed IS NULL)
|
||||
GROUP BY project_id
|
||||
) d ON p.project_id = d.project_id
|
||||
ORDER BY p.project_id;
|
||||
`;
|
||||
const result = await client.query(query);
|
||||
res.status(200).json(result.rows);
|
||||
} catch (err) {
|
||||
console.error("getProjects Error:", err);
|
||||
res.status(500).json({ error: "프로젝트 목록 조회 실패" });
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
};
|
||||
|
||||
exports.createProject = async (req, res) => {
|
||||
const { project_id, project_nm, short_nm, category, limit_storage, is_active } = req.body;
|
||||
if (!project_id || !project_nm) {
|
||||
return res.status(400).json({ error: "프로젝트 ID와 명칭은 필수입니다." });
|
||||
}
|
||||
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
// 중복 체크
|
||||
const dupRes = await client.query(`SELECT 1 FROM ver4.${tbProject} WHERE project_id = $1`, [project_id]);
|
||||
if (dupRes.rows.length > 0) {
|
||||
return res.status(400).json({ error: "이미 존재하는 프로젝트 ID입니다." });
|
||||
}
|
||||
|
||||
// storage_byte 계산 (GB -> Bytes)
|
||||
const storage_byte = limit_storage ? parseInt(limit_storage) * 1024 * 1024 * 1024 : 0;
|
||||
|
||||
const query = `
|
||||
INSERT INTO ver4.${tbProject} (project_id, project_nm, short_nm, category, storage_byte, is_active, user_id, create_date)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, CURRENT_TIMESTAMP)
|
||||
RETURNING *;
|
||||
`;
|
||||
const result = await client.query(query, [
|
||||
project_id,
|
||||
project_nm,
|
||||
short_nm || null,
|
||||
category || null,
|
||||
storage_byte,
|
||||
is_active ?? true,
|
||||
req.user?.user_id || 'admin'
|
||||
]);
|
||||
const userIp = req.headers['cf-connecting-ip'] || req.ip || req.headers['x-forwarded-for'] || req.connection?.remoteAddress;
|
||||
await insertAuditLog(project_id, 'createProject', req.user?.user_id, userIp, [
|
||||
`Project Name: ${project_nm}`,
|
||||
`Category: ${category}`,
|
||||
`Storage limit: ${limit_storage} GB`
|
||||
]);
|
||||
res.status(201).json(result.rows[0]);
|
||||
|
||||
} catch (err) {
|
||||
console.error("createProject Error:", err);
|
||||
res.status(500).json({ error: "프로젝트 생성 실패" });
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
};
|
||||
|
||||
exports.updateProject = async (req, res) => {
|
||||
const { id } = req.params;
|
||||
const { project_nm, short_nm, category, limit_storage, is_active } = req.body;
|
||||
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
const storage_byte = limit_storage ? parseInt(limit_storage) * 1024 * 1024 * 1024 : 0;
|
||||
const query = `
|
||||
UPDATE ver4.${tbProject}
|
||||
SET project_nm = $1, short_nm = $2, category = $3, storage_byte = $4, is_active = $5
|
||||
WHERE project_id = $6
|
||||
RETURNING *;
|
||||
`;
|
||||
const result = await client.query(query, [project_nm, short_nm || null, category || null, storage_byte, is_active, 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(id, 'updateProject', req.user?.user_id, userIp, [
|
||||
`Project Name: ${project_nm}`,
|
||||
`Category: ${category}`,
|
||||
`Storage limit: ${limit_storage} GB`,
|
||||
`Active status: ${is_active}`
|
||||
]);
|
||||
res.status(200).json(result.rows[0]);
|
||||
} catch (err) {
|
||||
console.error("updateProject Error:", err);
|
||||
res.status(500).json({ error: "프로젝트 수정 실패" });
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
};
|
||||
|
||||
exports.deleteProject = async (req, res) => {
|
||||
const { id } = req.params;
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
// [3대 삭제 제한 1] 프로젝트 사용 이력 체크
|
||||
// tb_data 사용 이력 검사
|
||||
const dataCountRes = await client.query(`SELECT COUNT(*) FROM ver4.${tbData} WHERE project_id = $1`, [id]);
|
||||
if (parseInt(dataCountRes.rows[0].count) > 0) {
|
||||
return res.status(400).json({ error: `해당 현장에 업로드된 파일 데이터(${dataCountRes.rows[0].count}건)가 존재하여 프로젝트를 삭제할 수 없습니다.` });
|
||||
}
|
||||
|
||||
// tb_official_doc_file 사용 이력 검사
|
||||
const docCountRes = await client.query("SELECT COUNT(*) FROM ver4.tb_official_doc_file WHERE project_id = $1", [id]);
|
||||
if (parseInt(docCountRes.rows[0].count) > 0) {
|
||||
return res.status(400).json({ error: `해당 현장에 연결된 공문서 파일(${docCountRes.rows[0].count}건)이 존재하여 프로젝트를 삭제할 수 없습니다.` });
|
||||
}
|
||||
|
||||
// tb_banner_notice 사용 이력 검사
|
||||
const noticeCountRes = await client.query("SELECT COUNT(*) FROM ver4.tb_banner_notice WHERE project_id = $1", [id]);
|
||||
if (parseInt(noticeCountRes.rows[0].count) > 0) {
|
||||
return res.status(400).json({ error: `해당 현장 전용 배너 공지 이력(${noticeCountRes.rows[0].count}건)이 존재하여 프로젝트를 삭제할 수 없습니다.` });
|
||||
}
|
||||
|
||||
// 통과 시 삭제 수행 (tb_permission 등 Cascade 관계는 수동으로 정리 가능하나, 안전을 위해 권한도 함께 정리함)
|
||||
await client.query(`DELETE FROM ver4.${tbPermission} WHERE project_id = $1`, [id]);
|
||||
const result = await client.query(`DELETE FROM ver4.${tbProject} WHERE project_id = $1 RETURNING *`, [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(id, 'deleteProject', req.user?.user_id, userIp, [
|
||||
`Deleted project name: ${result.rows[0].project_nm}`
|
||||
]);
|
||||
res.status(200).json({ message: "프로젝트가 정상적으로 삭제되었습니다." });
|
||||
} catch (err) {
|
||||
console.error("deleteProject Error:", err);
|
||||
res.status(500).json({ error: "프로젝트 삭제 실패" });
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
};
|
||||
|
||||
// 2. 프로젝트 권한 배정 (Permissions)
|
||||
exports.getProjectPermissions = async (req, res) => {
|
||||
const { projectId } = req.params;
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
const query = `
|
||||
SELECT pm.project_id, pm.user_id, pm.lev, u.user_nm, u.company, u.dept, u.position
|
||||
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 result = await client.query(query, [projectId]);
|
||||
res.status(200).json(result.rows);
|
||||
} catch (err) {
|
||||
console.error("getProjectPermissions Error:", err);
|
||||
res.status(500).json({ error: "권한 목록 조회 실패" });
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
};
|
||||
|
||||
exports.assignPermissions = async (req, res) => {
|
||||
const { project_id, users } = req.body; // users: [{ user_id, lev }]
|
||||
if (!project_id || !users || !Array.isArray(users) || users.length === 0) {
|
||||
return res.status(400).json({ error: "잘못된 요청 파라미터입니다." });
|
||||
}
|
||||
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
await client.query("BEGIN");
|
||||
for (const user of users) {
|
||||
await client.query(`
|
||||
INSERT INTO ver4.${tbPermission} (project_id, user_id, lev)
|
||||
VALUES ($1, $2, $3)
|
||||
ON CONFLICT (project_id, user_id)
|
||||
DO UPDATE SET lev = EXCLUDED.lev;
|
||||
`, [project_id, user.user_id, user.lev]);
|
||||
const userIp = req.headers['cf-connecting-ip'] || req.ip || req.headers['x-forwarded-for'] || req.connection?.remoteAddress;
|
||||
await insertAuditLog(project_id, 'assignPermission', req.user?.user_id, userIp, [
|
||||
`Assigned user_id: ${user.user_id}`,
|
||||
`Level assigned: ${user.lev}`
|
||||
]);
|
||||
}
|
||||
await client.query("COMMIT");
|
||||
res.status(200).json({ message: "사용자가 성공적으로 현장에 배정되었습니다." });
|
||||
} catch (err) {
|
||||
await client.query("ROLLBACK");
|
||||
console.error("assignPermissions Error:", err);
|
||||
res.status(500).json({ error: "사용자 권한 배정 실패" });
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
};
|
||||
|
||||
exports.updatePermission = async (req, res) => {
|
||||
const { project_id, user_id, lev } = req.body;
|
||||
if (!project_id || !user_id || lev === undefined) {
|
||||
return res.status(400).json({ error: "필수 파라미터가 누락되었습니다." });
|
||||
}
|
||||
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
const query = `
|
||||
UPDATE ver4.${tbPermission}
|
||||
SET lev = $1
|
||||
WHERE project_id = $2 AND user_id = $3
|
||||
RETURNING *;
|
||||
`;
|
||||
const result = await client.query(query, [lev, project_id, 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, 'updatePermission', req.user?.user_id, userIp, [
|
||||
`Updated user_id: ${user_id}`,
|
||||
`New level: ${lev}`
|
||||
]);
|
||||
res.status(200).json(result.rows[0]);
|
||||
} catch (err) {
|
||||
console.error("updatePermission Error:", err);
|
||||
res.status(500).json({ error: "권한 등급 수정 실패" });
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
};
|
||||
|
||||
exports.removePermission = async (req, res) => {
|
||||
const { project_id, user_id } = req.body;
|
||||
if (!project_id || !user_id) {
|
||||
return res.status(400).json({ error: "필수 파라미터가 누락되었습니다." });
|
||||
}
|
||||
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
const query = `
|
||||
DELETE FROM ver4.${tbPermission}
|
||||
WHERE project_id = $1 AND user_id = $2
|
||||
RETURNING *;
|
||||
`;
|
||||
const result = await client.query(query, [project_id, 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, 'removePermission', req.user?.user_id, userIp, [
|
||||
`Removed user_id: ${user_id}`
|
||||
]);
|
||||
res.status(200).json({ message: "사용자 배정이 제외되었습니다." });
|
||||
} catch (err) {
|
||||
console.error("removePermission Error:", err);
|
||||
res.status(500).json({ error: "사용자 배정 제외 실패" });
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
};
|
||||
|
||||
// 3. 실시간 배너 공지 (Banners)
|
||||
exports.getBanners = async (req, res) => {
|
||||
const { status, fromDate, toDate } = req.query;
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
let query = `
|
||||
SELECT b.*, p.project_nm, cd.code_nm as status_nm
|
||||
FROM ver4.tb_banner_notice b
|
||||
LEFT JOIN ver4.${tbProject} p ON b.project_id = p.project_id
|
||||
LEFT JOIN ver4.code_detail cd ON b.status_code = cd.base_code
|
||||
WHERE 1=1
|
||||
`;
|
||||
const params = [];
|
||||
let paramIndex = 1;
|
||||
|
||||
if (status && status !== 'all') {
|
||||
query += ` AND b.status_code = $${paramIndex++}`;
|
||||
params.push(status);
|
||||
}
|
||||
if (fromDate) {
|
||||
query += ` AND b.reg_date >= $${paramIndex++}`;
|
||||
params.push(fromDate);
|
||||
}
|
||||
if (toDate) {
|
||||
query += ` AND b.reg_date <= $${paramIndex++}`;
|
||||
params.push(toDate);
|
||||
}
|
||||
|
||||
query += ` ORDER BY b.banner_id DESC;`;
|
||||
const result = await client.query(query, params);
|
||||
res.status(200).json(result.rows);
|
||||
} catch (err) {
|
||||
console.error("getBanners Error:", err);
|
||||
res.status(500).json({ error: "배너 공지 목록 조회 실패" });
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
};
|
||||
|
||||
exports.createBanner = async (req, res) => {
|
||||
const { project_id, start_date, end_date, notice_text } = req.body;
|
||||
if (!start_date || !end_date || !notice_text) {
|
||||
return res.status(400).json({ error: "시작일, 종료일, 공지 자막은 필수입니다." });
|
||||
}
|
||||
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
// 송출 상태 계산 (오늘 기준)
|
||||
const today = new Date().toISOString().split('T')[0];
|
||||
let status_code = 'NOTICE_STATUS_scheduled';
|
||||
if (today >= start_date && today <= end_date) {
|
||||
status_code = 'NOTICE_STATUS_active';
|
||||
} else if (today > end_date) {
|
||||
status_code = 'NOTICE_STATUS_expired';
|
||||
}
|
||||
|
||||
const query = `
|
||||
INSERT INTO ver4.tb_banner_notice (project_id, start_date, end_date, notice_text, status_code, reg_date)
|
||||
VALUES ($1, $2, $3, $4, $5, CURRENT_DATE)
|
||||
RETURNING *;
|
||||
`;
|
||||
const result = await client.query(query, [
|
||||
project_id === 'all' || !project_id ? null : project_id,
|
||||
start_date,
|
||||
end_date,
|
||||
notice_text,
|
||||
status_code
|
||||
]);
|
||||
const userIp = req.headers['cf-connecting-ip'] || req.ip || req.headers['x-forwarded-for'] || req.connection?.remoteAddress;
|
||||
await insertAuditLog(project_id === 'all' || !project_id ? 'SYSTEM' : project_id, 'createBanner', req.user?.user_id, userIp, [
|
||||
`Banner text: ${notice_text}`,
|
||||
`Period: ${start_date} ~ ${end_date}`
|
||||
]);
|
||||
res.status(201).json(result.rows[0]);
|
||||
} catch (err) {
|
||||
console.error("createBanner Error:", err);
|
||||
res.status(500).json({ error: "배너 공지 생성 실패" });
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
};
|
||||
|
||||
exports.stopBanner = async (req, res) => {
|
||||
const { id } = req.params;
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
const query = `
|
||||
UPDATE ver4.tb_banner_notice
|
||||
SET status_code = 'NOTICE_STATUS_expired'
|
||||
WHERE banner_id = $1
|
||||
RETURNING *;
|
||||
`;
|
||||
const result = await client.query(query, [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(result.rows[0].project_id || 'SYSTEM', 'stopBanner', req.user?.user_id, userIp, [
|
||||
`Stopped banner_id: ${id}`,
|
||||
`Banner text: ${result.rows[0].notice_text}`
|
||||
]);
|
||||
res.status(200).json(result.rows[0]);
|
||||
} catch (err) {
|
||||
console.error("stopBanner Error:", err);
|
||||
res.status(500).json({ error: "배너 송출 중지 실패" });
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
};
|
||||
|
||||
// 4. 사용자 관리 (Users)
|
||||
exports.getUsers = async (req, res) => {
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
const query = `
|
||||
SELECT u.user_id, u.user_nm, u.company, u.dept, u.position, u.group, u.is_resigned, u.create_date, cd.code_nm as group_nm
|
||||
FROM ver4.tb_user u
|
||||
LEFT JOIN ver4.code_detail cd ON u.group = cd.base_code
|
||||
ORDER BY u.user_id;
|
||||
`;
|
||||
const result = await client.query(query);
|
||||
res.status(200).json(result.rows);
|
||||
} catch (err) {
|
||||
console.error("getUsers Error:", err);
|
||||
res.status(500).json({ error: "사용자 목록 조회 실패" });
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
};
|
||||
|
||||
exports.getUserPermissions = async (req, res) => {
|
||||
const { id } = req.params;
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
const query = `
|
||||
SELECT pm.project_id, p.project_nm, pm.lev
|
||||
FROM ver4.${tbPermission} pm
|
||||
JOIN ver4.${tbProject} p ON pm.project_id = p.project_id
|
||||
WHERE pm.user_id = $1
|
||||
ORDER BY p.project_nm ASC;
|
||||
`;
|
||||
const result = await client.query(query, [id]);
|
||||
res.status(200).json(result.rows);
|
||||
} catch (err) {
|
||||
console.error("getUserPermissions Error:", err);
|
||||
res.status(500).json({ error: "사용자 참여 현장 조회 실패" });
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
};
|
||||
|
||||
exports.createUser = async (req, res) => {
|
||||
const { user_id, user_nm, user_pw, company, dept, position, group, is_resigned } = req.body;
|
||||
if (!user_id || !user_nm || !user_pw) {
|
||||
return res.status(400).json({ error: "사용자 ID, 이름, 비밀번호는 필수입니다." });
|
||||
}
|
||||
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
// 중복 체크
|
||||
const dupRes = await client.query("SELECT 1 FROM ver4.tb_user WHERE user_id = $1", [user_id]);
|
||||
if (dupRes.rows.length > 0) {
|
||||
return res.status(400).json({ error: "이미 존재하는 사용자 ID입니다." });
|
||||
}
|
||||
|
||||
// 비밀번호 해싱 (SHA256 - GSIM 연동 상의 DB 제약 조건을 채우기 위함)
|
||||
const passwordHash = crypto.createHash('sha256').update(user_pw).digest('hex');
|
||||
|
||||
const query = `
|
||||
INSERT INTO ver4.tb_user (user_id, user_nm, user_pw, company, dept, position, "group", is_resigned, create_date)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, CURRENT_TIMESTAMP)
|
||||
RETURNING *;
|
||||
`;
|
||||
const result = await client.query(query, [
|
||||
user_id,
|
||||
user_nm,
|
||||
passwordHash,
|
||||
company || null,
|
||||
dept || null,
|
||||
position || null,
|
||||
group || null,
|
||||
is_resigned ?? false
|
||||
]);
|
||||
|
||||
const user = result.rows[0];
|
||||
const userIp = req.headers['cf-connecting-ip'] || req.ip || req.headers['x-forwarded-for'] || req.connection?.remoteAddress;
|
||||
await insertAuditLog('SYSTEM', 'createUser', req.user?.user_id, userIp, [
|
||||
`Created user_id: ${user_id}`,
|
||||
`User name: ${user_nm}`,
|
||||
`Group: ${group}`
|
||||
]);
|
||||
user.user_pw = undefined; // 비밀번호 제외
|
||||
res.status(201).json(user);
|
||||
} catch (err) {
|
||||
console.error("createUser Error:", err);
|
||||
res.status(500).json({ error: "사용자 생성 실패" });
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
};
|
||||
|
||||
exports.updateUser = async (req, res) => {
|
||||
const { id } = req.params;
|
||||
const { user_nm, company, dept, position, group, is_resigned } = req.body;
|
||||
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
const query = `
|
||||
UPDATE ver4.tb_user
|
||||
SET user_nm = $1, company = $2, dept = $3, position = $4, "group" = $5, is_resigned = $6
|
||||
WHERE user_id = $7
|
||||
RETURNING *;
|
||||
`;
|
||||
const result = await client.query(query, [
|
||||
user_nm,
|
||||
company || null,
|
||||
dept || null,
|
||||
position || null,
|
||||
group || null,
|
||||
is_resigned,
|
||||
id
|
||||
]);
|
||||
if (result.rows.length === 0) {
|
||||
return res.status(404).json({ error: "대상을 찾을 수 없습니다." });
|
||||
}
|
||||
|
||||
const user = result.rows[0];
|
||||
const userIp = req.headers['cf-connecting-ip'] || req.ip || req.headers['x-forwarded-for'] || req.connection?.remoteAddress;
|
||||
await insertAuditLog('SYSTEM', 'updateUser', req.user?.user_id, userIp, [
|
||||
`Updated user_id: ${id}`,
|
||||
`User name: ${user_nm}`,
|
||||
`Group: ${group}`,
|
||||
`Is resigned: ${is_resigned}`
|
||||
]);
|
||||
user.user_pw = undefined;
|
||||
res.status(200).json(user);
|
||||
} catch (err) {
|
||||
console.error("updateUser Error:", err);
|
||||
res.status(500).json({ error: "사용자 정보 수정 실패" });
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
};
|
||||
|
||||
exports.deleteUser = async (req, res) => {
|
||||
const { id } = req.params;
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
// [3대 삭제 제한 2] 사용자 삭제 시 권한 테이블 배정 정보 체크
|
||||
const permCountRes = await client.query(`SELECT COUNT(*) FROM ver4.${tbPermission} WHERE user_id = $1`, [id]);
|
||||
if (parseInt(permCountRes.rows[0].count) > 0) {
|
||||
return res.status(400).json({ error: `해당 사용자가 참여 중인 현장 권한(${permCountRes.rows[0].count}건)이 존재하여 계정을 삭제할 수 없습니다. 배정 해제 후 삭제 가능합니다.` });
|
||||
}
|
||||
|
||||
const result = await client.query("DELETE FROM ver4.tb_user WHERE user_id = $1 RETURNING *", [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('SYSTEM', 'deleteUser', req.user?.user_id, userIp, [
|
||||
`Deleted user_id: ${id}`
|
||||
]);
|
||||
res.status(200).json({ message: "사용자 계정이 성공적으로 삭제되었습니다." });
|
||||
} catch (err) {
|
||||
console.error("deleteUser Error:", err);
|
||||
res.status(500).json({ error: "사용자 삭제 실패" });
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
};
|
||||
|
||||
// 5. 감사 로그 조회 (Audit Logs)
|
||||
exports.getAuditLogs = async (req, res) => {
|
||||
const { user_id, activity } = 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}
|
||||
WHERE 1=1
|
||||
`;
|
||||
const params = [];
|
||||
let paramIndex = 1;
|
||||
|
||||
if (user_id) {
|
||||
query += ` AND user_id ILIKE $${paramIndex++}`;
|
||||
params.push(`%${user_id}%`);
|
||||
}
|
||||
if (activity && activity !== 'all') {
|
||||
query += ` AND activity = $${paramIndex++}`;
|
||||
params.push(activity);
|
||||
}
|
||||
|
||||
query += ` ORDER BY 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: "감사 로그 조회 실패" });
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
};
|
||||
|
||||
// 6. 보관 정책 설정 (Policies)
|
||||
exports.getSystemPolicy = async (req, res) => {
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
const result = await client.query("SELECT * FROM ver4.tb_system_policy WHERE policy_key = 'GLOBAL_DELETE_POLICY'");
|
||||
if (result.rows.length === 0) {
|
||||
// 기본 레코드 없을 시 생성해서 전송
|
||||
const insertRes = await client.query(`
|
||||
INSERT INTO ver4.tb_system_policy (policy_key, limit_file_count, limit_days, is_active)
|
||||
VALUES ('GLOBAL_DELETE_POLICY', 100, 30, FALSE)
|
||||
RETURNING *;
|
||||
`);
|
||||
return res.status(200).json(insertRes.rows[0]);
|
||||
}
|
||||
res.status(200).json(result.rows[0]);
|
||||
} catch (err) {
|
||||
console.error("getSystemPolicy Error:", err);
|
||||
res.status(500).json({ error: "보관 정책 조회 실패" });
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
};
|
||||
|
||||
exports.updateSystemPolicy = async (req, res) => {
|
||||
const { limit_file_count, limit_days, is_active } = req.body;
|
||||
if (limit_file_count === undefined || limit_days === undefined || is_active === undefined) {
|
||||
return res.status(400).json({ error: "필수 정책 입력값이 누락되었습니다." });
|
||||
}
|
||||
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
const query = `
|
||||
INSERT INTO ver4.tb_system_policy (policy_key, limit_file_count, limit_days, is_active, upd_date)
|
||||
VALUES ('GLOBAL_DELETE_POLICY', $1, $2, $3, CURRENT_TIMESTAMP)
|
||||
ON CONFLICT (policy_key)
|
||||
DO UPDATE SET limit_file_count = EXCLUDED.limit_file_count,
|
||||
limit_days = EXCLUDED.limit_days,
|
||||
is_active = EXCLUDED.is_active,
|
||||
upd_date = CURRENT_TIMESTAMP
|
||||
RETURNING *;
|
||||
`;
|
||||
const result = await client.query(query, [limit_file_count, limit_days, is_active]);
|
||||
const userIp = req.headers['cf-connecting-ip'] || req.ip || req.headers['x-forwarded-for'] || req.connection?.remoteAddress;
|
||||
await insertAuditLog('SYSTEM', 'updateSystemPolicy', req.user?.user_id, userIp, [
|
||||
`Limit file count: ${limit_file_count}`,
|
||||
`Limit days: ${limit_days}`,
|
||||
`Is active: ${is_active}`
|
||||
]);
|
||||
res.status(200).json(result.rows[0]);
|
||||
} catch (err) {
|
||||
console.error("updateSystemPolicy Error:", err);
|
||||
res.status(500).json({ error: "보관 정책 수정 실패" });
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
};
|
||||
|
||||
exports.getAutoCleanLogs = async (req, res) => {
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
const query = `
|
||||
SELECT log_id, clean_date, project_id, clean_path, criteria_info, result_status
|
||||
FROM ver4.tb_auto_clean_log
|
||||
ORDER BY log_id DESC LIMIT 100;
|
||||
`;
|
||||
const result = await client.query(query);
|
||||
res.status(200).json(result.rows);
|
||||
} catch (err) {
|
||||
console.error("getAutoCleanLogs Error:", err);
|
||||
res.status(500).json({ error: "배치 이력 조회 실패" });
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
};
|
||||
|
||||
// 7. 공통 코드 관리 (Common Codes)
|
||||
exports.getCodeMasters = async (req, res) => {
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
const query = "SELECT * FROM ver4.code_master ORDER BY main_code;";
|
||||
const result = await client.query(query);
|
||||
res.status(200).json(result.rows);
|
||||
} catch (err) {
|
||||
console.error("getCodeMasters Error:", err);
|
||||
res.status(500).json({ error: "대분류 마스터 코드 조회 실패" });
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
};
|
||||
|
||||
exports.createCodeMaster = async (req, res) => {
|
||||
const { main_code, main_code_nm, use_yn, rmk } = req.body;
|
||||
if (!main_code || !main_code_nm) {
|
||||
return res.status(400).json({ error: "대분류 코드와 명칭은 필수입니다." });
|
||||
}
|
||||
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
const dupRes = await client.query("SELECT 1 FROM ver4.code_master WHERE main_code = $1", [main_code]);
|
||||
if (dupRes.rows.length > 0) {
|
||||
return res.status(400).json({ error: "이미 존재하는 대분류 코드입니다." });
|
||||
}
|
||||
|
||||
const query = `
|
||||
INSERT INTO ver4.code_master (main_code, main_code_nm, use_yn, rmk)
|
||||
VALUES ($1, $2, $3, $4)
|
||||
RETURNING *;
|
||||
`;
|
||||
const result = await client.query(query, [main_code, main_code_nm, use_yn ?? 'Y', rmk || null]);
|
||||
const userIp = req.headers['cf-connecting-ip'] || req.ip || req.headers['x-forwarded-for'] || req.connection?.remoteAddress;
|
||||
await insertAuditLog('SYSTEM', 'createCodeMaster', req.user?.user_id, userIp, [
|
||||
`Master code: ${main_code}`,
|
||||
`Master code name: ${main_code_nm}`
|
||||
]);
|
||||
res.status(201).json(result.rows[0]);
|
||||
} catch (err) {
|
||||
console.error("createCodeMaster Error:", err);
|
||||
res.status(500).json({ error: "대분류 등록 실패" });
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
};
|
||||
|
||||
exports.updateCodeMaster = async (req, res) => {
|
||||
const { code } = req.params;
|
||||
const { main_code_nm, use_yn, rmk } = req.body;
|
||||
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
const query = `
|
||||
UPDATE ver4.code_master
|
||||
SET main_code_nm = $1, use_yn = $2, rmk = $3
|
||||
WHERE main_code = $4
|
||||
RETURNING *;
|
||||
`;
|
||||
const result = await client.query(query, [main_code_nm, use_yn, rmk || null, code]);
|
||||
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('SYSTEM', 'updateCodeMaster', req.user?.user_id, userIp, [
|
||||
`Updated master code: ${code}`,
|
||||
`New code name: ${main_code_nm}`,
|
||||
`Use YN: ${use_yn}`
|
||||
]);
|
||||
res.status(200).json(result.rows[0]);
|
||||
} catch (err) {
|
||||
console.error("updateCodeMaster Error:", err);
|
||||
res.status(500).json({ error: "대분류 수정 실패" });
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
};
|
||||
|
||||
exports.deleteCodeMaster = async (req, res) => {
|
||||
const { code } = req.params;
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
// [3대 삭제 제한 3] 대분류 삭제 시 하위 세부 코드 존재 체크
|
||||
const detailCountRes = await client.query("SELECT COUNT(*) FROM ver4.code_detail WHERE main_code = $1", [code]);
|
||||
if (parseInt(detailCountRes.rows[0].count) > 0) {
|
||||
return res.status(400).json({ error: `해당 대분류에 기속된 세부 소분류 코드(${detailCountRes.rows[0].count}건)가 존재하여 대분류를 삭제할 수 없습니다.` });
|
||||
}
|
||||
|
||||
const result = await client.query("DELETE FROM ver4.code_master WHERE main_code = $1 RETURNING *", [code]);
|
||||
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('SYSTEM', 'deleteCodeMaster', req.user?.user_id, userIp, [
|
||||
`Deleted master code: ${code}`
|
||||
]);
|
||||
res.status(200).json({ message: "대분류 코드가 삭제되었습니다." });
|
||||
} catch (err) {
|
||||
console.error("deleteCodeMaster Error:", err);
|
||||
res.status(500).json({ error: "대분류 삭제 실패" });
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
};
|
||||
|
||||
exports.getCodeDetails = async (req, res) => {
|
||||
const { mainCode } = req.params;
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
const query = "SELECT * FROM ver4.code_detail WHERE main_code = $1 ORDER BY sort_ord, sub_code;";
|
||||
const result = await client.query(query, [mainCode]);
|
||||
res.status(200).json(result.rows);
|
||||
} catch (err) {
|
||||
console.error("getCodeDetails Error:", err);
|
||||
res.status(500).json({ error: "소분류 세부 코드 조회 실패" });
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
};
|
||||
|
||||
exports.createCodeDetail = async (req, res) => {
|
||||
const { main_code, sub_code, code_nm, sort_ord, use_yn, rmk } = req.body;
|
||||
if (!main_code || !sub_code || !code_nm) {
|
||||
return res.status(400).json({ error: "대분류, 소분류 코드 및 코드 명칭은 필수입니다." });
|
||||
}
|
||||
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
const dupRes = await client.query("SELECT 1 FROM ver4.code_detail WHERE main_code = $1 AND sub_code = $2", [main_code, sub_code]);
|
||||
if (dupRes.rows.length > 0) {
|
||||
return res.status(400).json({ error: "해당 대분류 내에 이미 존재하는 소분류 코드입니다." });
|
||||
}
|
||||
|
||||
// 조합 코드 (base_code) 자동 조합: main_code || '_' || sub_code
|
||||
const base_code = `${main_code}_${sub_code}`;
|
||||
|
||||
const query = `
|
||||
INSERT INTO ver4.code_detail (main_code, sub_code, base_code, code_nm, sort_ord, use_yn, rmk)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
||||
RETURNING *;
|
||||
`;
|
||||
const result = await client.query(query, [main_code, sub_code, base_code, code_nm, sort_ord ?? 1, use_yn ?? 'Y', rmk || null]);
|
||||
const userIp = req.headers['cf-connecting-ip'] || req.ip || req.headers['x-forwarded-for'] || req.connection?.remoteAddress;
|
||||
await insertAuditLog('SYSTEM', 'createCodeDetail', req.user?.user_id, userIp, [
|
||||
`Master code: ${main_code}`,
|
||||
`Sub code: ${sub_code}`,
|
||||
`Code name: ${code_nm}`
|
||||
]);
|
||||
res.status(201).json(result.rows[0]);
|
||||
} catch (err) {
|
||||
console.error("createCodeDetail Error:", err);
|
||||
res.status(500).json({ error: "소분류 등록 실패" });
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
};
|
||||
|
||||
exports.updateCodeDetail = async (req, res) => {
|
||||
const { mainCode, subCode } = req.params;
|
||||
const { code_nm, sort_ord, use_yn, rmk } = req.body;
|
||||
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
const query = `
|
||||
UPDATE ver4.code_detail
|
||||
SET code_nm = $1, sort_ord = $2, use_yn = $3, rmk = $4
|
||||
WHERE main_code = $5 AND sub_code = $6
|
||||
RETURNING *;
|
||||
`;
|
||||
const result = await client.query(query, [code_nm, sort_ord, use_yn, rmk || null, mainCode, subCode]);
|
||||
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('SYSTEM', 'updateCodeDetail', req.user?.user_id, userIp, [
|
||||
`Master code: ${mainCode}`,
|
||||
`Sub code: ${subCode}`,
|
||||
`New code name: ${code_nm}`
|
||||
]);
|
||||
res.status(200).json(result.rows[0]);
|
||||
} catch (err) {
|
||||
console.error("updateCodeDetail Error:", err);
|
||||
res.status(500).json({ error: "소분류 수정 실패" });
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
};
|
||||
|
||||
// 7-4. 소분류 코드 삭제
|
||||
exports.deleteCodeDetail = async (req, res) => {
|
||||
const { mainCode, subCode } = req.params;
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
const query = `
|
||||
DELETE FROM ver4.code_detail
|
||||
WHERE main_code = $1 AND sub_code = $2
|
||||
RETURNING *;
|
||||
`;
|
||||
const result = await client.query(query, [mainCode, subCode]);
|
||||
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('SYSTEM', 'deleteCodeDetail', req.user?.user_id, userIp, [
|
||||
`Master code: ${mainCode}`,
|
||||
`Sub code: ${subCode}`
|
||||
]);
|
||||
res.status(200).json({ message: "소분류 코드가 삭제되었습니다." });
|
||||
} catch (err) {
|
||||
console.error("deleteCodeDetail Error:", err);
|
||||
res.status(500).json({ error: "소분류 삭제 실패" });
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
};
|
||||
4359
controllers/archiveController.js
Normal file
4359
controllers/archiveController.js
Normal file
File diff suppressed because it is too large
Load Diff
448
controllers/authController.js
Normal file
448
controllers/authController.js
Normal file
@@ -0,0 +1,448 @@
|
||||
const passport = require('passport');
|
||||
const pool = require('../db/pool.js');
|
||||
const env = process.env.NODE_ENV;
|
||||
const tbProject = env === 'production' ? 'tb_project' : '_test_tb_project';
|
||||
const tbPermission = env === 'production' ? 'tb_permission' : '_test_tb_permission';
|
||||
|
||||
|
||||
//////// pm-bcmf 연결용 테스트 코드 - pm-bcmf url에 담겨있던 쿼리 정보 저장, 조회
|
||||
let bcmfId, startPath;
|
||||
exports.setBcmfUrlQuery = async (req,res)=>{
|
||||
bcmfId = req.body.id;
|
||||
startPath = req.body.startPath;
|
||||
}
|
||||
exports.getBcmfUrlQuery = async (req,res)=>{
|
||||
res.status(200).json({
|
||||
bcmfId: bcmfId,
|
||||
startPath: startPath
|
||||
});
|
||||
}
|
||||
exports.getBcmfId = () => {
|
||||
return bcmfId;
|
||||
}
|
||||
|
||||
// passport.initialize()와 passport.session()를 추가해야 req.isAuthenticated() 함수를 사용할 수 있음.
|
||||
exports.isLoggedIn = async(req,res,next)=>{
|
||||
if (req.isAuthenticated()) { // 패스포트를 통해 로그인 했는지를 확인
|
||||
console.log('🚥 [authController] isLoggedIn? : ture');
|
||||
|
||||
next();
|
||||
} else {
|
||||
// 1) 주소를 요청: http://localhost:3000/zip/status/?url=a.glb&url=b.glb
|
||||
// 2) 로그인 페이지(html)로 이동(쿼리스트링으로 path에 주소 넣음): http://localhost:3000/login?path=/zip/status/?url=a.glb&url=b.glb
|
||||
// 3) 로그인 이후 원래 주소로 이동: http://localhost:3000/zip/status/?url=a.glb&url=b.glb
|
||||
console.log('🚥 [authController] isLoggedIn? : false');
|
||||
res.redirect('/user/login?path='+req.originalUrl);//=> 로그인X인경우 이동할 페이지
|
||||
}
|
||||
}
|
||||
|
||||
exports.isNotLoggedIn = async(req,res,next)=>{
|
||||
if(!req.isAuthenticated()){
|
||||
console.log('🚥 [authController] isNotLoggedIn? : true');
|
||||
next();
|
||||
}else{
|
||||
console.log('🚥 [authController] isNotLoggedIn? : false');
|
||||
// const html = `
|
||||
// <html>
|
||||
// <body>
|
||||
// <h3>로그인을 이미 했습니다</h3>
|
||||
// <a class="btn-logout" href="/auth/logout">로그아웃</a>
|
||||
// <br>
|
||||
// <a href="/">index 화면으로 이동</a>
|
||||
// </body>
|
||||
// </html>
|
||||
// `;
|
||||
// res.send(html);
|
||||
// res.status(200).json({redirect : req.})
|
||||
next();//로그인 상태에서 로그인 요청 시 그냥 로그인 절차 밟도록 수정
|
||||
}
|
||||
}
|
||||
|
||||
exports.login =async(req,res,next)=>{
|
||||
//진입 시도페이지로 다시 보내기위한 쿼리
|
||||
const newQuery = req.query.path ? decodeURIComponent(req.query.path) : '/';
|
||||
console.log('🌏 [authController.js] newQuery :', newQuery);
|
||||
|
||||
|
||||
//서비스 이름 넣기
|
||||
// req.body.service = 'PM_ver4';
|
||||
req.body.service = process.env.SERVICE_NAME +' - ' + req.headers['origin'];
|
||||
|
||||
// 접근 아이피 넣기
|
||||
/**
|
||||
* cf-connecting-ip: Cloudflare가 원본 클라이언트 IP를 전달하는 헤더
|
||||
* x-forwarded-for: 일반적인 프록시 체인 헤더
|
||||
* req.ip: Express가 계산한 IP (trust proxy 설정 시 의미 있음)
|
||||
* remoteAddress: 실제 TCP 연결의 IP
|
||||
*/
|
||||
req.body.user_ip = req.headers['cf-connecting-ip'] || req.ip || req.headers['x-forwarded-for'] || req.connection.remoteAddress;
|
||||
|
||||
if (req.body.startPath) req.session.startPath = req.body.startPath;
|
||||
|
||||
passport.authenticate('local', (authError, user, info)=>{
|
||||
if(authError){
|
||||
console.error(authError);
|
||||
return next(authError);
|
||||
}
|
||||
|
||||
if(!user){
|
||||
return res.json({error:info.message});
|
||||
}
|
||||
|
||||
return req.login(user, async (loginError)=>{
|
||||
//로그인 후 행위등록 - ex log추가...
|
||||
if(loginError){
|
||||
console.error(loginError);
|
||||
return next(loginError);
|
||||
}
|
||||
return res.json({redirect:newQuery, user:user});
|
||||
});
|
||||
}) (req,res,next);
|
||||
}
|
||||
|
||||
exports.logout = async (req,res,next)=>{
|
||||
//////// pm-bcmf 연결용 테스트 코드 - 로그아웃할 때 bcmfId, startPath 초기화
|
||||
bcmfId = undefined;
|
||||
startPath = undefined;
|
||||
|
||||
req.logout(()=>{
|
||||
//기본페이지로 redirect
|
||||
// res.redirect('/user/login');
|
||||
res.redirect('/user/login?path=/');
|
||||
})
|
||||
}
|
||||
|
||||
//로그인 상태 확인
|
||||
exports.status = async(req,res,next)=>{
|
||||
if(req.user){
|
||||
const client = await pool.connect();
|
||||
try{
|
||||
if(!req.user.permission || req.user.permission ==null){
|
||||
let {project_id} = req.query;
|
||||
if (project_id && project_id !== 'undefined' && project_id !== 'null') {
|
||||
let queryString = `
|
||||
select
|
||||
case
|
||||
when exists (select 1 from ver4.${tbProject} where project_id = '${project_id}' and user_id = '${req.user.user_id}')
|
||||
then 255
|
||||
else (
|
||||
select lev
|
||||
from ver4.${tbPermission}
|
||||
where project_id = '${project_id}' and user_id = '${req.user.user_id}'
|
||||
)
|
||||
end as lev
|
||||
`;
|
||||
let {rows} = await client.query(queryString);
|
||||
req.user.permission = rows[0]?.lev || null;
|
||||
} else {
|
||||
req.user.permission = null;
|
||||
}
|
||||
}
|
||||
let queryString2 = `select bookmark from ver4.tb_user where user_id = '${req.user.user_id}'`;
|
||||
let bookmarkRes = await client.query(queryString2);
|
||||
req.user.bookmark = bookmarkRes.rows[0]?.bookmark || '';
|
||||
|
||||
req.user.user_pw = undefined;
|
||||
res.json({loggedIn : true, user : req.user});
|
||||
}catch(err){
|
||||
console.error('🚨 [authController.status] Error:', err);
|
||||
res.status(500).json({loggedIn : false, error: err.message});
|
||||
}finally{
|
||||
client.release();
|
||||
}
|
||||
}else{
|
||||
res.json({loggedIn : false});
|
||||
}
|
||||
}
|
||||
|
||||
//권한 설정 관련
|
||||
|
||||
// 권한 부여용 멤버 가져오기
|
||||
exports.getMemberList = async (req,res,next)=>{
|
||||
let {project_id} = req.query;
|
||||
const client = await pool.connect();
|
||||
try{
|
||||
let queryString = `select user_id, user_nm, company, dept, position from ver4.tb_user
|
||||
where ("group" is null or "group" = '') and is_resigned = false
|
||||
order by user_nm asc`;
|
||||
|
||||
let {rows} = await client.query(queryString);
|
||||
let permissionQuery = `select user_id, CASE lev WHEN 191 THEN 'sub-master' WHEN 15 THEN 'security-worker' WHEN 7 THEN 'worker' WHEN 3 THEN 'uploader' WHEN 1 THEN 'viewer' END as lev from ver4.${tbPermission} where project_id = $1`;
|
||||
let permissionRes = await client.query(permissionQuery, [project_id]);
|
||||
|
||||
res.status(200).json({all : rows, permission : permissionRes.rows});
|
||||
}catch(err){
|
||||
console.error(err);
|
||||
}finally{
|
||||
client.release();
|
||||
}
|
||||
}
|
||||
|
||||
//권한 수정(json Array 로 받아서 parse후 처리)
|
||||
/* project_id : 단일, a_per, target_id, target_name : 배열 */
|
||||
exports.upsertPermission = async(req, res, next)=>{
|
||||
let {project_id , targetArr, userInfoString } = req.body;
|
||||
// let actor_user_id = req.user.user_id;
|
||||
// let user_nm = req.user.user_nm;
|
||||
// let activity_id = 'addUserPermission';
|
||||
// let dateNow = makePostgresTimestamp(Date.now());
|
||||
let userIp = req.ip;
|
||||
|
||||
const client = await pool.connect();
|
||||
try{
|
||||
let queryString = `insert into ver4.${tbPermission} (user_id, project_id, lev) values `;
|
||||
for(let i = 0; i < targetArr.length; i++){
|
||||
queryString += ` ('${targetArr[i].user_id}','${project_id}',${getPermissionLev(targetArr[i].lev)})${(i==targetArr.length-1)?'':','} `;
|
||||
}
|
||||
queryString += `on conflict (user_id, project_id) do update set
|
||||
lev = EXCLUDED.lev
|
||||
RETURNING *`;
|
||||
let upsertRes = await client.query(queryString);
|
||||
if(upsertRes.rows.length == targetArr.length){// 권한 부여 성공
|
||||
// 유저권한 renderlog code
|
||||
let group = {};
|
||||
for (const user of targetArr){
|
||||
if(!group[user.lev]) group[user.lev] = {lev: user.lev, before: user.before , userIds: [], names : []}
|
||||
group[user.lev].userIds.push(user.user_id);
|
||||
group[user.lev].names.push(user.user_nm);
|
||||
}
|
||||
|
||||
const permissionArr = Object.values(group);
|
||||
const levMap = { 'sub-master' : 'addPermission_subMaster', 'security-worker' : 'addPermission_securityWorker'};
|
||||
// 로그를 담기 위한 배열
|
||||
const logs = [];
|
||||
for (const p of permissionArr){
|
||||
let activity = levMap[p.lev] || `addPermission_${p.lev}`
|
||||
let params = { projectId : project_id, activity, userInfoString, userIp, resourcePathArr: p.names, dataIdArr: p.userIds}
|
||||
logs.push(params)
|
||||
};
|
||||
// upsert success와 함께 logs 배열 res
|
||||
res.status(200).json({message : 'upsert success', logs});
|
||||
}else{
|
||||
res.status(500).json({message : 'upsert error'});
|
||||
}
|
||||
}catch(err){
|
||||
console.error(err);
|
||||
res.status(500).json({message : 'upsert error'});
|
||||
}finally{
|
||||
client.release();
|
||||
}
|
||||
}
|
||||
|
||||
//권한 삭제
|
||||
exports.deletePermission = async(req, res, next)=>{
|
||||
let {project_id, targetArr, userInfoString} = req.body;
|
||||
let userIp = req.ip;
|
||||
|
||||
const client = await pool.connect();
|
||||
try{
|
||||
const conditions = targetArr.map((item, index) => {
|
||||
return `(project_id = $1 AND user_id = $${index + 2})`;
|
||||
}).join(' OR ');
|
||||
|
||||
let queryString = `DELETE FROM ver4.${tbPermission} WHERE ${conditions} RETURNING *`;
|
||||
|
||||
const params = [project_id, ...targetArr.map(item => item.user_id)];
|
||||
|
||||
let deleteRes = await client.query(queryString, params);
|
||||
|
||||
if(deleteRes.rows.length == targetArr.length){ //delete 성공
|
||||
|
||||
// 유저권한 renderlog code
|
||||
let group = {};
|
||||
for(const user of targetArr){
|
||||
// 권한 삭제 경우 기존 권한 before를 바탕으로 로그에 넣어준다.
|
||||
if(!group[user.before]) group[user.before] = {lev: user.before, before: user.lev, userIds: [], names: []};
|
||||
group[user.before].userIds.push(user.user_id);
|
||||
group[user.before].names.push(user.user_nm);
|
||||
}
|
||||
|
||||
const permissionArr = Object.values(group);
|
||||
const levMap = { 'sub-master' : 'deletePermission_subMaster', 'security-worker' : 'deletePermission_securityWorker'}
|
||||
// 로그를 담기 위한 배열
|
||||
const logs = [];
|
||||
for (const p of permissionArr){
|
||||
let activity = levMap[p.lev] || `deletePermission_${p.lev}`
|
||||
let params = {projectId : project_id , activity, userInfoString, userIp, resourcePathArr : p.names, dataIdArr : p.userIds}
|
||||
logs.push(params);
|
||||
};
|
||||
// delete success와 함께 logs 배열 res
|
||||
res.status(200).json({message : 'delete success', logs});
|
||||
}else{//delete 실패
|
||||
res.status(500).json({message : 'delete error'});
|
||||
}
|
||||
}catch(err){
|
||||
console.error(err);
|
||||
}finally{
|
||||
client.release();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 회사-부서 목록
|
||||
exports.getDeptList = async (req, res, next) => {
|
||||
const company = req.query.company;
|
||||
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
let queryString = 'SELECT DISTINCT dept FROM ver4.tb_user WHERE company = $1 AND is_resigned = false';
|
||||
let queryResult = await client.query(queryString, [company]);
|
||||
res.status(200).json({message : '200', result : queryResult.rows})
|
||||
} catch(err) {
|
||||
console.error('getCompanyList Error : ', err);
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
}
|
||||
|
||||
// 회사-부서-유저 목록
|
||||
exports.getUserList = async (req, res, next) => {
|
||||
const company = req.query.company;
|
||||
const dept = req.query.dept;
|
||||
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
let queryString = `SELECT user_id, user_nm, company, dept, position, is_resigned
|
||||
FROM ver4.tb_user
|
||||
WHERE company = $1
|
||||
AND dept = $2
|
||||
AND is_resigned = false
|
||||
ORDER BY
|
||||
CASE
|
||||
WHEN position = '회장' THEN 1
|
||||
WHEN position = '부회장' THEN 2
|
||||
WHEN position = '사장' THEN 3
|
||||
WHEN position = '상임고문' THEN 4
|
||||
WHEN position = '기술위원' THEN 5
|
||||
WHEN position = '부사장' THEN 6
|
||||
WHEN position = '고문' THEN 7
|
||||
WHEN position = '전무이사' THEN 8
|
||||
WHEN position = '수석연구원' THEN 9
|
||||
WHEN position = '상무이사' THEN 10
|
||||
WHEN position = '이사' THEN 11
|
||||
WHEN position = '책임연구원' THEN 12
|
||||
WHEN position = '부장' THEN 13
|
||||
WHEN position = '차장' THEN 14
|
||||
WHEN position = '선임연구원' THEN 15
|
||||
WHEN position = '과장' THEN 16
|
||||
WHEN position = '연구원' THEN 17
|
||||
WHEN position = '대리' THEN 18
|
||||
WHEN position = '사원' THEN 19
|
||||
ELSE 99
|
||||
END,
|
||||
user_nm ASC`;
|
||||
let queryResult = await client.query(queryString, [company, dept]);
|
||||
res.status(200).json({message : '200', result : queryResult.rows});
|
||||
} catch(err) {
|
||||
console.error('getUserList Error : ', err);
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
}
|
||||
|
||||
exports.getPermissionUserInfo = async (req, res, next) => {
|
||||
const permission = req.body.permission;
|
||||
|
||||
const userIds = permission.map(p => p.user_id).filter(user_id => !user_id.includes('dev')).filter(user_id => !user_id.includes('SAVANNAH')).filter(user_id => !user_id.includes('ECHO')).filter(user_id => !user_id.includes('VOID')).filter(user_id => !user_id.includes('STRIKE')).filter(user_id => !user_id.includes('CHILL')).filter(user_id => !user_id.includes('NOIR')).filter(user_id => !user_id.includes('LESSER'));
|
||||
|
||||
const client = await pool.connect();
|
||||
try{
|
||||
let queryString = `SELECT user_id, user_nm, company, dept, position, is_resigned
|
||||
FROM ver4.tb_user
|
||||
WHERE user_id = ANY($1::text[]) AND is_resigned = false
|
||||
ORDER BY
|
||||
CASE
|
||||
WHEN position = '회장' THEN 1
|
||||
WHEN position = '부회장' THEN 2
|
||||
WHEN position = '사장' THEN 3
|
||||
WHEN position = '상임고문' THEN 4
|
||||
WHEN position = '기술위원' THEN 5
|
||||
WHEN position = '부사장' THEN 6
|
||||
WHEN position = '고문' THEN 7
|
||||
WHEN position = '전무이사' THEN 8
|
||||
WHEN position = '수석연구원' THEN 9
|
||||
WHEN position = '상무이사' THEN 10
|
||||
WHEN position = '이사' THEN 11
|
||||
WHEN position = '책임연구원' THEN 12
|
||||
WHEN position = '부장' THEN 13
|
||||
WHEN position = '차장' THEN 14
|
||||
WHEN position = '선임연구원' THEN 15
|
||||
WHEN position = '과장' THEN 16
|
||||
WHEN position = '연구원' THEN 17
|
||||
WHEN position = '대리' THEN 18
|
||||
WHEN position = '사원' THEN 19
|
||||
ELSE 99
|
||||
END,
|
||||
user_nm ASC`;
|
||||
let queryResult = await client.query(queryString, [userIds]);
|
||||
res.status(200).json({message : '200', result : queryResult.rows});
|
||||
} catch(err) {
|
||||
console.error('getPermissionUserInfo Error : ')
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//내부용 함수
|
||||
// 날짜 formatter
|
||||
function formatDate(date){
|
||||
const year = date.getFullYear();
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(date.getDate()).padStart(2, '0');
|
||||
const hours = String(date.getHours()).padStart(2, '0');
|
||||
const minutes = String(date.getMinutes()).padStart(2, '0');
|
||||
const seconds = String(date.getSeconds()).padStart(2, '0');
|
||||
|
||||
return `${year}. ${month}. ${day}. ${hours}:${minutes}:${seconds}`;
|
||||
}
|
||||
|
||||
// 권한 lev string=>number
|
||||
function getPermissionLev(lev){
|
||||
let result;
|
||||
|
||||
switch(lev){
|
||||
case 'sub-master':
|
||||
result = 191;
|
||||
break;
|
||||
case 'security-worker':
|
||||
result = 15;
|
||||
break;
|
||||
case 'worker':
|
||||
result = 7;
|
||||
break;
|
||||
// case 'uploader':
|
||||
// result = 3;
|
||||
// break;
|
||||
case 'viewer':
|
||||
result = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 권한 lev number => string (우선 select에서 case when then으로 처리)
|
||||
function getPermissionName(lev){
|
||||
let result;
|
||||
switch(lev){
|
||||
case 191:
|
||||
result = 'sub-master';
|
||||
break;
|
||||
case 15:
|
||||
result = 'security-worker';
|
||||
break;
|
||||
case 7:
|
||||
result = 'worker';
|
||||
break;
|
||||
// case 3:
|
||||
// result = 'uploader';
|
||||
// break;
|
||||
case 1:
|
||||
result = 'viewer';
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
40
controllers/bullBoardController.js
Normal file
40
controllers/bullBoardController.js
Normal file
@@ -0,0 +1,40 @@
|
||||
// controllers/monitorController.js
|
||||
const { createBullBoard } = require('@bull-board/api');
|
||||
const { BullMQAdapter } = require('@bull-board/api/bullMQAdapter.js');
|
||||
const { ExpressAdapter } = require('@bull-board/express');
|
||||
const { Queue } = require('bullmq');
|
||||
|
||||
const { redisConnection } = require('../config/redis.js');
|
||||
|
||||
// 1) 모니터링할 큐 인스턴스화
|
||||
const convertQueue = new Queue('convert-pdf', { connection: redisConnection });
|
||||
const convertQueue2 = new Queue('pdf-thumb', { connection: redisConnection });
|
||||
const convertQueue3 = new Queue('zip-folder', { connection: redisConnection });
|
||||
const convertQueue4 = new Queue('post-process-video', { connection: redisConnection });
|
||||
const convertQueue5 = new Queue('ai-summarize', { connection: redisConnection });
|
||||
const convertQueue6 = new Queue('api-summarize', {connection: redisConnection});
|
||||
// const convertQueue3 = new Queue('test-job', { connection: redisConnection });
|
||||
|
||||
// 2) ExpressAdapter 생성 및 기본 경로 설정
|
||||
const serverAdapter = new ExpressAdapter();
|
||||
serverAdapter.setBasePath('/admin/queues');
|
||||
|
||||
// 3) Bull-Board 생성
|
||||
createBullBoard({
|
||||
queues: [
|
||||
new BullMQAdapter(convertQueue),
|
||||
new BullMQAdapter(convertQueue2),
|
||||
new BullMQAdapter(convertQueue3),
|
||||
new BullMQAdapter(convertQueue4),
|
||||
new BullMQAdapter(convertQueue5),
|
||||
new BullMQAdapter(convertQueue6),
|
||||
// new BullMQAdapter(convertQueue3),
|
||||
// 여기에 더 필요한 큐 어댑터를 추가할 수 있습니다.
|
||||
],
|
||||
serverAdapter,
|
||||
});
|
||||
|
||||
// 4) 실제 대시보드를 처리하는 Router 추출
|
||||
const bullBoardController = serverAdapter.getRouter();
|
||||
|
||||
module.exports = bullBoardController;
|
||||
320
controllers/commonController.js
Normal file
320
controllers/commonController.js
Normal file
@@ -0,0 +1,320 @@
|
||||
const pool = require('../db/pool.js');
|
||||
const env = process.env.NODE_ENV;
|
||||
const { getIo } = require('../socket.js');
|
||||
|
||||
const tbProject = env == 'production'? 'tb_project':'_test_tb_project';
|
||||
const tbPermission = env == 'production'? 'tb_permission':'_test_tb_permission';
|
||||
|
||||
|
||||
function snakeToCamel(snakeStr) {
|
||||
return snakeStr.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
|
||||
}
|
||||
|
||||
exports.getEnvData = async (req,res,next)=>{
|
||||
const deploymentType = process.env.DEPLOYMENT_TYPE;
|
||||
const cloudType = process.env.CLOUD_TYPE;
|
||||
const serviceName = process.env.SERVICE_NAME;
|
||||
res.status(200).json({
|
||||
message : 'getEnvData',
|
||||
deploymentType: deploymentType,
|
||||
cloudType: cloudType,
|
||||
serviceName: serviceName,
|
||||
});
|
||||
}
|
||||
|
||||
exports.getProject = async (req,res,next)=>{
|
||||
let {project_id} = req.query;
|
||||
const client = await pool.connect();
|
||||
//////// 원본코드
|
||||
// let user_id = req.user.user_id;
|
||||
// let user_group = req.user.group;
|
||||
|
||||
//////// pm-bcmf 연결용 테스트 코드 - pm-bcmf url로 접속하면 정상적으로 로그인이 되지 않아 req.user가 없기 때문에 user_id, user_group 강제 설정
|
||||
let user_id = (req.user) ? req.user.user_id : undefined;
|
||||
let user_group = (req.user) ? req.user.group : undefined;
|
||||
|
||||
const authController = require('../controllers/authController');
|
||||
let bcmfId = await authController.getBcmfId();
|
||||
if (bcmfId && bcmfId.includes('bcmf-')) {
|
||||
user_id = bcmfId;
|
||||
user_group = 'bcmf';
|
||||
}
|
||||
|
||||
try {
|
||||
// 테스트
|
||||
let queryString = `
|
||||
select p.*, u.*
|
||||
from ver4.${tbProject} p
|
||||
inner join ver4.tb_user u
|
||||
on p.user_id = u.user_id
|
||||
where show_in_index = true
|
||||
`;
|
||||
|
||||
// let queryString = `
|
||||
// select p.*, u.*
|
||||
// from ver4.${tbProject} p
|
||||
// inner join ver4.tb_user u
|
||||
// on p.user_id = u.user_id
|
||||
// where show_in_index = true
|
||||
// `;
|
||||
|
||||
if(!user_group){
|
||||
queryString += `and ( p.user_id = '${user_id}' or p.project_id in (select project_id from ver4.${tbPermission} where user_id = '${user_id}')) `;
|
||||
}
|
||||
|
||||
// 251223 dev계정도 총괄 제한
|
||||
if(user_group != 'super'){
|
||||
queryString += ` and ( (p.project_type != 'secret' or p.project_type is null )
|
||||
or exists (select 1 from ver4.${tbPermission} tp where tp.project_id = p.project_id and tp.user_id = '${user_id}')
|
||||
) `;
|
||||
}
|
||||
|
||||
if(project_id && project_id != '')
|
||||
queryString += `and project_id = '${project_id}' `;
|
||||
queryString += `order by p.create_date`;
|
||||
|
||||
console.log(queryString);
|
||||
const {rows} = await client.query(queryString);
|
||||
res.status(200).json({message : 'getProject', data: rows});
|
||||
} catch(err) {
|
||||
console.error(err);
|
||||
res.status(500).json({message : 'getProject error'});
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
}
|
||||
|
||||
exports.mgmtFunc_updateProject = async (req,res)=>{
|
||||
let { params } = req.body;
|
||||
let { projectIdList, targetColumn, state, text } = params;
|
||||
|
||||
let value;
|
||||
if (targetColumn == 'is_active') value = state;
|
||||
if (targetColumn == 'banner_notice') value = text;
|
||||
|
||||
let projectArr = JSON.parse(projectIdList);
|
||||
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
await client.query('BEGIN');
|
||||
|
||||
let updateQueryString = `
|
||||
UPDATE ver4.${tbProject}
|
||||
SET ${targetColumn} = $1
|
||||
WHERE project_id = ANY($2)
|
||||
`;
|
||||
|
||||
let selectQueryString = `
|
||||
SELECT p.*, u.*
|
||||
FROM ver4.${tbProject} p
|
||||
INNER JOIN ver4.tb_user u
|
||||
ON p.user_id = u.user_id
|
||||
WHERE show_in_index = true;
|
||||
`;
|
||||
|
||||
await client.query(updateQueryString, [value, projectArr]);
|
||||
let { rows } = await client.query(selectQueryString);
|
||||
|
||||
await client.query('COMMIT');
|
||||
|
||||
params.allProject = rows;
|
||||
|
||||
let successMessage = `updateProject_${snakeToCamel(targetColumn)}_success`;
|
||||
|
||||
let io = getIo();
|
||||
io.emit(successMessage, params);
|
||||
|
||||
res.status(200).json({
|
||||
message: successMessage,
|
||||
});
|
||||
|
||||
} catch(err) {
|
||||
console.error("updateProject err:", err);
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
exports.getVersion = async(req,res,next)=>{
|
||||
res.status(200).json({
|
||||
message : 'getVersion success',
|
||||
version : process.env.PROJECT_VERSION
|
||||
});
|
||||
}
|
||||
|
||||
// 🔻🔻🔻🔻🔻🔻🔻🔻 LIST화면용 함수 시작 🔻🔻🔻🔻🔻🔻🔻🔻
|
||||
|
||||
//프로젝트 (권한 있는) 목록들 가져오기
|
||||
exports.getProjects = async (req,res,next) => {
|
||||
let user_id = req.user.user_id;
|
||||
const client = await pool.connect();
|
||||
|
||||
try{
|
||||
let queryString = `select project_id, user_id, category, project_nm, create_date, lon, lat, height, step, emp_map, flyto from ver4.${tbProject} where project_id in (select project_id from ver4.${tbPermission} where user_id = $1)`;
|
||||
const {rows} = await client.query(queryString, [user_id]);
|
||||
|
||||
res.status(200).json({message : 'getProjects', data : rows});
|
||||
}catch(err){
|
||||
console.error(err);
|
||||
res.status(500).json({message : 'getProjects error'});
|
||||
}finally{
|
||||
client.release();
|
||||
}
|
||||
}
|
||||
|
||||
//북마크 프로젝트들 가져오기
|
||||
exports.getBookmark = async (req,res,next) =>{
|
||||
let user_id = req.user.user_id;
|
||||
const client = await pool.connect();
|
||||
|
||||
try{
|
||||
let queryString = `select project_id, user_id, category, project_nm, create_date, lon, lat, height, step, emp_map, flyto from ver4.tb_project where project_id in (select unnest(string_to_array(bookmark, ',')) from ver4.tb_user where user_id = $1)`;
|
||||
const {rows} = await client.query(queryString, [user_id]);
|
||||
|
||||
res.status(200).json({message : 'getBookmark', data : rows});
|
||||
}catch(err){
|
||||
console.error(err);
|
||||
res.status(500).json({message : 'getBookmark error'});
|
||||
}finally{
|
||||
client.release();
|
||||
}
|
||||
}
|
||||
|
||||
//북마크 update (JS의 array.toString() 형태로 넣기.)
|
||||
exports.updateBookmark = async (req, res, next) =>{
|
||||
let user_id = req.user.user_id;
|
||||
const {bookmark} = req.query;
|
||||
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
let queryString = `update ver4.tb_user set bookmark = $1 where user_id = $2`;
|
||||
await client.query(queryString, [bookmark, user_id]);
|
||||
res.status(200).json({message : `updateBookmark`});
|
||||
}catch(err){
|
||||
console.error(err);
|
||||
res.status(500).json({message : `updateBookmark error`});
|
||||
}finally{
|
||||
client.release();
|
||||
}
|
||||
}
|
||||
|
||||
// 🔺🔺🔺🔺🔺🔺🔺🔺 LIST화면용 함수 끝 🔺🔺🔺🔺🔺🔺🔺🔺
|
||||
|
||||
// 프로젝트 정보 업데이트
|
||||
exports.updateProjectInfo = async (req, res) => {
|
||||
let { params } = req.body;
|
||||
|
||||
let result = await updateProjectInfoAction(params);
|
||||
|
||||
res.status(200).json(result);
|
||||
}
|
||||
|
||||
async function updateProjectInfoAction(params) {
|
||||
const client = await pool.connect();
|
||||
|
||||
try {
|
||||
const {
|
||||
projectId,
|
||||
category,
|
||||
project_nm,
|
||||
project_type,
|
||||
step,
|
||||
} = params
|
||||
|
||||
// let queryString;
|
||||
|
||||
// if(category !== 'overseas' && category !== 'bimproject') {
|
||||
// queryString = `
|
||||
// UPDATE ver4.${tbProject}
|
||||
// SET
|
||||
// project_type = $1,
|
||||
// step = $2,
|
||||
// project_nm = $3
|
||||
// WHERE project_id = $4
|
||||
// AND category = $5
|
||||
// `;
|
||||
// } else {
|
||||
let queryString = `
|
||||
UPDATE ver4.${tbProject}
|
||||
SET
|
||||
project_type = $1,
|
||||
step = $2,
|
||||
short_nm = $3
|
||||
WHERE project_id = $4
|
||||
AND category = $5
|
||||
`;
|
||||
// }
|
||||
|
||||
let values = [project_type, step, project_nm, projectId, category];
|
||||
|
||||
let { rows } = await client.query(queryString, values);
|
||||
return { message: 'updateProjectInfo_success'};
|
||||
|
||||
} catch(err) {
|
||||
console.error('updateProjectInfoAction err : ', err);
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
}
|
||||
|
||||
// 프로젝트 위치 업데이트
|
||||
exports.updateLocationInfo = async (req, res) => {
|
||||
let { params } = req.body;
|
||||
|
||||
let result = await updateLocationInfoAction(params);
|
||||
|
||||
res.status(200).json(result);
|
||||
}
|
||||
|
||||
async function updateLocationInfoAction(params) {
|
||||
const client = await pool.connect();
|
||||
|
||||
try {
|
||||
const {
|
||||
projectId,
|
||||
category,
|
||||
project_nm,
|
||||
lon,
|
||||
lat,
|
||||
} = params
|
||||
|
||||
let queryString = `
|
||||
UPDATE ver4.${tbProject}
|
||||
SET
|
||||
lon = $1,
|
||||
lat = $2
|
||||
WHERE project_id = $3
|
||||
AND category = $4
|
||||
AND project_nm = $5
|
||||
RETURNING lon, lat;
|
||||
`;
|
||||
|
||||
let values = [lon, lat, projectId, category, project_nm];
|
||||
|
||||
let { rows } = await client.query(queryString, values);
|
||||
return { message: 'updateLocationInfo_success', data: rows[0] };
|
||||
|
||||
} catch(err) {
|
||||
console.error('updateLocationInfoAction err : ', err);
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
}
|
||||
|
||||
// 일반 사용자용 보존/삭제 정책 조회 API
|
||||
exports.getSystemPolicyPublic = async (req, res, next) => {
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
const result = await client.query("SELECT limit_file_count, limit_days, is_active FROM ver4.tb_system_policy WHERE policy_key = 'GLOBAL_DELETE_POLICY'");
|
||||
if (result.rows.length === 0) {
|
||||
return res.status(200).json({ limit_file_count: 100, limit_days: 30, is_active: false });
|
||||
}
|
||||
res.status(200).json(result.rows[0]);
|
||||
} catch (err) {
|
||||
console.error("getSystemPolicyPublic error:", err);
|
||||
res.status(500).json({ message: "정책 조회 중 오류가 발생했습니다." });
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
};
|
||||
295
controllers/gsimController.js
Normal file
295
controllers/gsimController.js
Normal file
@@ -0,0 +1,295 @@
|
||||
const pool = require('../db/pool.js');
|
||||
const env = process.env.NODE_ENV;
|
||||
const tbProject = env === 'production' ? 'tb_project' : '_test_tb_project';
|
||||
const tbPermission = env === 'production' ? 'tb_permission' : '_test_tb_permission';
|
||||
const cloudClient = require('../config/cloudClient.js');
|
||||
|
||||
const { getSignedUrl } = require('@aws-sdk/s3-request-presigner');
|
||||
const {
|
||||
ListObjectsV2Command,
|
||||
DeleteObjectCommand,
|
||||
CopyObjectCommand,
|
||||
HeadObjectCommand,
|
||||
PutObjectCommand,
|
||||
GetObjectCommand,
|
||||
ListBucketsCommand
|
||||
} = require('@aws-sdk/client-s3');
|
||||
|
||||
// 🔻🔻🔻🔻🔻🔻🔻🔻 리스트관련 함수 시작 🔻🔻🔻🔻🔻🔻🔻🔻
|
||||
// 분류 가져오기
|
||||
exports.getListClass = async(req, res, next) =>{
|
||||
const {steps, search} = req.query;
|
||||
const client = await pool.connect();
|
||||
let user_id = req.user.user_id;
|
||||
let user_group = req.user.group;
|
||||
|
||||
try{
|
||||
let queryString = `select b.class ,b.large_class, b.mid_class from ver4.${tbProject} a, ver4.ref_project_class b
|
||||
where a.class = b.class and a.show_in_index = true `;
|
||||
|
||||
if(!user_group){
|
||||
queryString += `and ( a.user_id = '${user_id}' or a.project_id in (select project_id from ver4.${tbPermission} where user_id = '${user_id}')) `;
|
||||
}
|
||||
|
||||
if(steps){
|
||||
//입력되는 필더 조건에 따라 변경예정
|
||||
queryString += `and a.step in ( `;
|
||||
for(let i =0; i < steps.length; i++){
|
||||
queryString += ` '${steps[i]}' ${(i < steps.length-1)?',':''}`
|
||||
}
|
||||
queryString += ` ) `;
|
||||
}
|
||||
|
||||
if(search != '' && search != null && search != undefined){
|
||||
queryString += ` and UPPER(a.project_nm) like '%${search}%' `;
|
||||
}
|
||||
|
||||
queryString += ` order by b.class asc`;
|
||||
|
||||
const {rows} = await client.query(queryString);
|
||||
|
||||
//순서때문에 client에서 받아서 처리
|
||||
res.status(200).json({data : rows});
|
||||
}catch(err){
|
||||
console.error(err);
|
||||
res.status(500).json({message : 'getDepth1 error'});
|
||||
}finally{
|
||||
client.release();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//depth3 list불러오기
|
||||
exports.getList = async (req,res,next) =>{
|
||||
const {steps, classNo, search } = req.query;
|
||||
const client = await pool.connect();
|
||||
let user_id = req.user.user_id;
|
||||
let user_group = req.user.group;
|
||||
|
||||
try{
|
||||
// let queryString = `select * from ver4.tb_project where project_id in (select unnest(string_to_array(bookmark, ',')) from ver4.tb_user where user_id = $1)`;
|
||||
let queryString = `select a.project_id, a.category, a.project_nm, a.lon, a.lat, a.height, a.step, a.emp_map, a.flyto, b.user_id, b.user_nm, b.company, b.dept, a.class, b.position
|
||||
from ver4.${tbProject} a, ver4.tb_user b where a.user_id = b.user_id and a.show_in_index = true and a.class = ${classNo} `;
|
||||
|
||||
if(steps){
|
||||
//입력되는 필더 조건에 따라 변경예정
|
||||
queryString += `and a.step in ( `;
|
||||
for(let i =0; i < steps.length; i++){
|
||||
queryString += ` '${steps[i]}' ${(i < steps.length-1)?',':''}`
|
||||
}
|
||||
queryString += ` ) `;
|
||||
}
|
||||
|
||||
if(!user_group){
|
||||
queryString += `and ( a.user_id = '${user_id}' or a.project_id in (select project_id from ver4.${tbPermission} where user_id = '${user_id}')) `;
|
||||
}
|
||||
|
||||
if(search != '' && search != null && search != undefined){
|
||||
queryString += ` and UPPER(a.project_nm) like '%${search}%' `;
|
||||
}
|
||||
|
||||
queryString += `order by project_id, project_nm asc`;
|
||||
|
||||
const {rows} = await client.query(queryString);
|
||||
|
||||
res.status(200).json({message : 'getModelList', data : rows});
|
||||
}catch(err){
|
||||
console.error(err);
|
||||
res.status(500).json({message : 'getModelList error'});
|
||||
}finally{
|
||||
client.release();
|
||||
}
|
||||
}
|
||||
|
||||
// 🔺🔺🔺🔺🔺🔺🔺🔺 리스트관련 함수 끝 🔺🔺🔺🔺🔺🔺🔺🔺
|
||||
|
||||
// 🔻🔻🔻🔻🔻🔻🔻🔻 북마크관련 함수 시작 🔻🔻🔻🔻🔻🔻🔻🔻
|
||||
exports.updateBookmark = async(req,res,next)=>{
|
||||
const {bookmark} = req.query;
|
||||
let user_id = req.user.user_id;
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
let queryString = `update ver4.tb_user set bookmark = $1 where user_id = $2`;
|
||||
|
||||
const { rows } = await client.query(queryString, [bookmark,user_id]);
|
||||
res.status(200).json({ message: 'updateBookmark Done'});
|
||||
}catch(error) {
|
||||
console.error("updateBookmark err:", error);
|
||||
}finally {
|
||||
client.release();
|
||||
}
|
||||
}
|
||||
// 🔺🔺🔺🔺🔺🔺🔺🔺 북마크관련 함수 끝 🔺🔺🔺🔺🔺🔺🔺🔺
|
||||
|
||||
|
||||
exports.projectstatusList = async(req,res,next)=>{
|
||||
const client = await pool.connect();
|
||||
try{
|
||||
let queryString = `select * from ver4.test_tb_projectstatus order by create_date`;
|
||||
const {rows} = await client.query(queryString);
|
||||
res.status(200).json({message : 'projectstatusList', data : rows});
|
||||
}catch(err){
|
||||
console.error(err);
|
||||
res.status(500).json({message : 'projectstatusList error'});
|
||||
}finally{
|
||||
client.release();
|
||||
}
|
||||
}
|
||||
|
||||
exports.getPresignedUrl = async(req, res, next) =>{
|
||||
const {bucket, objectKey} = req.query;
|
||||
try{
|
||||
let command = new GetObjectCommand({
|
||||
Bucket: bucket,
|
||||
Key: objectKey,
|
||||
});
|
||||
|
||||
//cloudClient에 강제로 던지기
|
||||
let url = await getSignedUrl(cloudClient, command, { expiresIn: 60 * 30 }); // 30분 유효
|
||||
|
||||
res.status(200).json({message : 'getProsignedUrl', data : url});
|
||||
|
||||
}catch(err){
|
||||
console.error(err);
|
||||
res.status(500).json({message : 'getProsignedUrl error'});
|
||||
}
|
||||
}
|
||||
|
||||
exports.uploadUrl = async(req, res, next) => {
|
||||
const {filename} = req.query;
|
||||
try{
|
||||
const command = new PutObjectCommand({
|
||||
Bucket: 'gsimdev',
|
||||
Key: `projectStatus/${filename}`,
|
||||
ContentType: 'application/pdf'
|
||||
});
|
||||
//cloudClient에 강제로 던지기
|
||||
let url = await getSignedUrl(cloudClient, command, { expiresIn: 60 * 30 }); // 30분 유효
|
||||
|
||||
res.status(200).json({message : 'uploadUrl', data : url});
|
||||
|
||||
}catch(err){
|
||||
console.error(err);
|
||||
res.status(500).json({message : 'uploadUrl error'});
|
||||
}
|
||||
}
|
||||
|
||||
exports.insertProjectStatusData = async(req, res, next) => {
|
||||
const {filename} = req.query;
|
||||
const client = await pool.connect();
|
||||
try{
|
||||
let queryString = `insert into ver4.test_tb_projectstatus (file_nm, object_key, bucket) values ($1, $2, $3) returning *`;
|
||||
const {rows} = await client.query(queryString, [filename, `projectStatus/${filename}`, 'gsimdev']);
|
||||
res.status(200).json({message : 'insertProjectStatusData', data : rows});
|
||||
}catch(err){
|
||||
console.error(err);
|
||||
res.status(500).json({message : 'insertProjectStatusData error'});
|
||||
}finally{
|
||||
client.release();
|
||||
}
|
||||
}
|
||||
|
||||
//우선 DB만 삭제
|
||||
exports.deleteFile = async(req, res, next) => {
|
||||
const {objectKey, bucket} = req.query;
|
||||
const client = await pool.connect();
|
||||
try{
|
||||
let queryString = `delete from ver4.test_tb_projectstatus where object_key = $1 and bucket = $2 returning *`;
|
||||
const {rows} = await client.query(queryString, [objectKey, bucket]);
|
||||
res.status(200).json({message : 'deleteFile', data : rows});
|
||||
}catch(err){
|
||||
console.error(err);
|
||||
res.status(500).json({message : 'deleteFile error'});
|
||||
}finally{
|
||||
client.release();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 🔻🔻🔻🔻🔻🔻🔻🔻 new! 리스트관련 함수 시작 🔻🔻🔻🔻🔻🔻🔻🔻
|
||||
// 전체 리스트 가져오기
|
||||
exports.getAllList = async(req, res, next) =>{
|
||||
const {steps, search, type, category} = req.query;
|
||||
const client = await pool.connect();
|
||||
|
||||
let user_id = req.user.user_id;
|
||||
let user_group = req.user.group;
|
||||
|
||||
try{
|
||||
let queryString = `select b.class ,b.large_class, b.mid_class, a.*, (select user_nm from ver4.tb_user where user_id = a.user_id) as master from ver4.${tbProject} a, ver4.ref_project_class b
|
||||
where a.class = b.class and a.show_in_index = true and category = '${category}' `;
|
||||
|
||||
if(!user_group){
|
||||
queryString += `and ( a.user_id = '${user_id}' or a.project_id in (select project_id from ver4.${tbPermission} where user_id = '${user_id}')) `;
|
||||
}
|
||||
|
||||
if(steps && steps != 'overseas'){
|
||||
//입력되는 필더 조건에 따라 변경
|
||||
queryString += `and a.step in ( `;
|
||||
for(let i =0; i < steps.length; i++){
|
||||
queryString += ` '${steps[i]}' ${(i < steps.length-1)?',':''}`
|
||||
}
|
||||
queryString += ` ) `;
|
||||
}
|
||||
|
||||
if(type && type != 'overseas'){
|
||||
//입력되는 필더 조건에 따라 변경
|
||||
queryString += `and a.project_type in ( `;
|
||||
for(let i =0; i < type.length; i++){
|
||||
queryString += ` '${type[i]}' ${(i < type.length-1)?',':''}`
|
||||
}
|
||||
queryString += ` ) `;
|
||||
}
|
||||
|
||||
if(search != '' && search != null && search != undefined){
|
||||
queryString += ` and UPPER(a.project_nm) like '%${search}%' `;
|
||||
}
|
||||
|
||||
if(steps == 'overseas' || type == 'overseas'){
|
||||
queryString += ` and a.category = 'overseas' `;
|
||||
}
|
||||
|
||||
queryString += ` order by b.class asc`;
|
||||
|
||||
const {rows} = await client.query(queryString);
|
||||
|
||||
//순서때문에 client에서 받아서 처리
|
||||
res.status(200).json({data : rows});
|
||||
}catch(err){
|
||||
console.error(err);
|
||||
res.status(500).json({message : 'getDepth1 error'});
|
||||
}finally{
|
||||
client.release();
|
||||
}
|
||||
}
|
||||
// 🔺🔺🔺🔺🔺🔺🔺🔺 new! 리스트관련 함수 끝 🔺🔺🔺🔺🔺🔺🔺🔺
|
||||
|
||||
exports.setProjectType = async (req,res, next)=>{
|
||||
const {project_id, type} = req.query;
|
||||
const client = await pool.connect();
|
||||
try{
|
||||
let query = `update ver4.tb_project set project_type = $1 where project_id = $2 returning *`;
|
||||
const {rows} = await client.query(query, [type, project_id]);
|
||||
res.status(200).json({message : 'setProjectTypeSuccess', data : rows});
|
||||
}catch(err){
|
||||
console.error(err);
|
||||
res.status(500).json({message : 'setProjectType error'});
|
||||
}finally{
|
||||
client.release();
|
||||
}
|
||||
}
|
||||
|
||||
exports.setProjectStep = async (req,res, next)=>{
|
||||
const {project_id, step} = req.query;
|
||||
const client = await pool.connect();
|
||||
try{
|
||||
let query = `update ver4.tb_project set step = $1 where project_id = $2 returning *`;
|
||||
const {rows} = await client.query(query, [step, project_id]);
|
||||
res.status(200).json({message : 'setProjectStepSuccess', data : rows});
|
||||
}catch(err){
|
||||
console.error(err);
|
||||
res.status(500).json({message : 'setProjectStep error'});
|
||||
}finally{
|
||||
client.release();
|
||||
}
|
||||
}
|
||||
1362
controllers/officialDocController.js
Normal file
1362
controllers/officialDocController.js
Normal file
File diff suppressed because it is too large
Load Diff
710
controllers/overviewController.js
Normal file
710
controllers/overviewController.js
Normal file
@@ -0,0 +1,710 @@
|
||||
const path = require('path');
|
||||
const pool = require('../db/pool.js');
|
||||
const fs = require('fs');
|
||||
const multer = require('multer');
|
||||
const { getSignedUrl } = require('@aws-sdk/s3-request-presigner');
|
||||
const { PutObjectCommand, GetObjectCommand, DeleteObjectCommand } = require('@aws-sdk/client-s3');
|
||||
|
||||
const onPremiseClient = require('../config/onPremiseClient.js');
|
||||
const cloudClient = require('../config/cloudClient.js');
|
||||
const storageClients = {
|
||||
'ONPREMISE': onPremiseClient,
|
||||
'CLOUD': cloudClient
|
||||
}
|
||||
|
||||
const deploymentType = process.env.DEPLOYMENT_TYPE;
|
||||
const s3 = storageClients[deploymentType];
|
||||
|
||||
exports.getData = async (req, res, next) => {
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
let { projectId } = req.query;
|
||||
let queryString = `
|
||||
select project_id,
|
||||
project_no,
|
||||
business_purpose,
|
||||
location_img,
|
||||
continent,
|
||||
performance_area,
|
||||
reference_area,
|
||||
overview_img,
|
||||
facility_size_overview,
|
||||
task_nm_kr,
|
||||
task_nm_en,
|
||||
task_purpose,
|
||||
task_type,
|
||||
client,
|
||||
financial,
|
||||
financial_country,
|
||||
bid,
|
||||
selection_method,
|
||||
joint_contract_nm,
|
||||
joint_contract_shareratio,
|
||||
contract_amount,
|
||||
foreign_currency_amount,
|
||||
contract_date,
|
||||
commencement_date,
|
||||
original_completion_date,
|
||||
completion_date,
|
||||
projectmanager_nm,
|
||||
manager_nm,
|
||||
nation_nm,
|
||||
client_origin,
|
||||
support_department,
|
||||
support_manager_nm,
|
||||
representative_company,
|
||||
order_size_krw,
|
||||
order_size_usd,
|
||||
scheuled_commencement_date,
|
||||
contract_period,
|
||||
abbreviated_name,
|
||||
department,
|
||||
data_size,
|
||||
issue,
|
||||
currency_code,
|
||||
joint_contract,
|
||||
lead_company,
|
||||
nation_code,
|
||||
nation_offset
|
||||
from ver4.tb_overview
|
||||
where project_id = $1;
|
||||
`;
|
||||
const result = await client.query(queryString, [projectId]);
|
||||
res.json({
|
||||
success: true,
|
||||
message: '200',
|
||||
data: result.rows,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('getData error: ', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '500',
|
||||
error: error.message,
|
||||
});
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
};
|
||||
|
||||
exports.getCalendarEventData = async (req, res) => {
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
let { nationName, projectId, currentYear, currentMonth } = req.query;
|
||||
let queryString = `
|
||||
SELECT
|
||||
calendar_event_id,
|
||||
project_id,
|
||||
type,
|
||||
title,
|
||||
content,
|
||||
color,
|
||||
start_date,
|
||||
end_date,
|
||||
nation_nm
|
||||
FROM ver4.tb_calendar_event
|
||||
WHERE (
|
||||
(type = 'holiday' AND nation_nm IN ('한국', $1)) OR
|
||||
(type = 'schedule' AND project_id = $2)
|
||||
)
|
||||
AND EXTRACT(YEAR FROM TO_DATE(start_date, 'YYYY-MM-DD')) = $3
|
||||
AND EXTRACT(MONTH FROM TO_DATE(start_date, 'YYYY-MM-DD')) = $4;
|
||||
|
||||
`
|
||||
const result = await client.query(queryString, [nationName, projectId, currentYear, currentMonth]);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: '200',
|
||||
data: result.rows,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('getCalendarEventData error: ', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '500',
|
||||
error: error.message
|
||||
});
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
}
|
||||
|
||||
exports.getTaskPeriodData = async (req, res) => {
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
let { projectId } = req.query;
|
||||
let queryString = `
|
||||
SELECT
|
||||
task_history_id,
|
||||
project_id,
|
||||
task_order,
|
||||
suspension_date,
|
||||
suspension_reason,
|
||||
resumption_date,
|
||||
consultation_content,
|
||||
change_date
|
||||
FROM ver4.tb_task_history
|
||||
WHERE project_id = $1;
|
||||
`;
|
||||
const result = await client.query(queryString, [projectId]);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: '200',
|
||||
data: result.rows,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('getTaskPeriodData error: ', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '500',
|
||||
error: error.message,
|
||||
});
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
};
|
||||
|
||||
exports.getFacilitySizeData = async (req, res) => {
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
let { projectId } = req.query;
|
||||
let queryString = `
|
||||
SELECT
|
||||
facility_id,
|
||||
project_id,
|
||||
key,
|
||||
value,
|
||||
title
|
||||
FROM ver4.tb_facility_size AS t
|
||||
WHERE project_id = $1
|
||||
ORDER BY
|
||||
(SELECT MIN(facility_id)
|
||||
FROM ver4.tb_facility_size
|
||||
WHERE title = t.title),
|
||||
facility_id;
|
||||
`;
|
||||
const result = await client.query(queryString, [projectId]);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: '200',
|
||||
data: result.rows,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('getFacilitySizeData error: ', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '500',
|
||||
error: error.message,
|
||||
});
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
};
|
||||
|
||||
exports.saveScheduleData = async (req, res) => {
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
let {scheduleId, projectId, title, content, color, startDateTimeStr, endDateTimeStr, country } = req.body;
|
||||
const type = 'schedule';
|
||||
|
||||
let queryString;
|
||||
let result;
|
||||
if(scheduleId === undefined){
|
||||
queryString = `
|
||||
INSERT INTO ver4.tb_calendar_event (project_id, type, title, content, color, start_date, end_date, nation_nm)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
||||
`
|
||||
result = await client.query(queryString, [projectId, type, title, content, color, startDateTimeStr, endDateTimeStr, country]);
|
||||
} else {
|
||||
queryString = `
|
||||
INSERT INTO ver4.tb_calendar_event (calendar_event_id, project_id, type, title, content, color, start_date, end_date, nation_nm)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
|
||||
ON CONFLICT (calendar_event_id) DO UPDATE SET
|
||||
project_id = EXCLUDED.project_id,
|
||||
type = EXCLUDED.type,
|
||||
title = EXCLUDED.title,
|
||||
content = EXCLUDED.content,
|
||||
color = EXCLUDED.color,
|
||||
start_date = EXCLUDED.start_date,
|
||||
end_date = EXCLUDED.end_date,
|
||||
nation_nm = EXCLUDED.nation_nm
|
||||
`;
|
||||
result = await client.query(queryString, [scheduleId, projectId, type, title, content, color, startDateTimeStr, endDateTimeStr, country]);
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: '200',
|
||||
data: result.rows,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('saveScheduleData error: ', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '500',
|
||||
error: error.message,
|
||||
});
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
}
|
||||
|
||||
exports.deleteScheduleData = async (req, res) => {
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
let { scheduleId } = req.body;
|
||||
let queryString = `
|
||||
DELETE FROM ver4.tb_calendar_event
|
||||
WHERE calendar_event_id = $1;
|
||||
`;
|
||||
const result = await client.query(queryString, [scheduleId]);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: '200',
|
||||
data: result.rows,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('deleteScheduleData error: ', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '500',
|
||||
error: error.message,
|
||||
});
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
};
|
||||
|
||||
exports.deleteTaskPeriodData = async (req, res) => {
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
let { deleteArr } = req.body;
|
||||
|
||||
let queryString = `
|
||||
DELETE FROM ver4.tb_task_history
|
||||
WHERE task_history_id = ANY($1);
|
||||
`;
|
||||
const result = await client.query(queryString, [deleteArr]);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: '200',
|
||||
data: result.rows,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('deleteTaskHistory error: ', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '500',
|
||||
error: error.message,
|
||||
});
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
};
|
||||
|
||||
exports.deleteSectionData = async (req, res) => {
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
let { title } = req.body;
|
||||
let queryString = `
|
||||
DELETE FROM ver4.tb_facility_size
|
||||
WHERE title = $1;
|
||||
`;
|
||||
const result = await client.query(queryString, [title]);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: '200',
|
||||
data: result.rows,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('deleteSectionData error: ', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '500',
|
||||
error: error.message,
|
||||
});
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
};
|
||||
|
||||
exports.deleteCellData = async (req, res) => {
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
let { deleteArr } = req.body;
|
||||
const ids = deleteArr.map(cell => cell.id);
|
||||
|
||||
let queryString = `
|
||||
DELETE FROM ver4.tb_facility_size
|
||||
WHERE facility_id = ANY($1);
|
||||
`;
|
||||
const result = await client.query(queryString, [ids]);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: '200',
|
||||
data: result.rows,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('deleteCellData error: ', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '500',
|
||||
error: error.message,
|
||||
});
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
exports.deleteLocationImgData = async (req, res) => {
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
let { projectId } = req.body;
|
||||
let queryString = `
|
||||
UPDATE ver4.tb_overview
|
||||
SET location_img = ''
|
||||
WHERE project_id = $1;
|
||||
`;
|
||||
const result = await client.query(queryString, [projectId]);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: '200',
|
||||
data: result.rows,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('updateLocationImgData error: ', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '500',
|
||||
error: error.message,
|
||||
});
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
};
|
||||
|
||||
exports.deleteOverviewImgData = async (req, res) => {
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
let { projectId } = req.body;
|
||||
let queryString = `
|
||||
UPDATE ver4.tb_overview
|
||||
SET overview_img = ''
|
||||
WHERE project_id = $1;
|
||||
`;
|
||||
const result = await client.query(queryString, [projectId]);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: '200',
|
||||
data: result.rows,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('updateLocationImgData error: ', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '500',
|
||||
error: error.message,
|
||||
});
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
};
|
||||
|
||||
exports.saveSectionLeftData = async (req, res, next) => {
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
let {projectId, businessPurpose, continent, performanceArea, referenceArea, nation, facilityOverview, locationImgKey, originFileSize } = req.body;
|
||||
|
||||
let values = [projectId, businessPurpose, continent, performanceArea, referenceArea, nation, facilityOverview, locationImgKey, originFileSize];
|
||||
|
||||
let queryString = `
|
||||
INSERT INTO ver4.tb_overview ( project_id, business_purpose, continent, performance_area, reference_area, nation_nm, facility_size_overview, location_img, data_size)
|
||||
VALUES ( $1, $2, $3, $4, $5, $6, $7, $8, $9)
|
||||
ON CONFLICT (project_id)
|
||||
DO UPDATE SET business_purpose = EXCLUDED.business_purpose, location_img = EXCLUDED.location_img, continent = EXCLUDED.continent,performance_area = EXCLUDED.performance_area, reference_area = EXCLUDED.reference_area, data_size = EXCLUDED.data_size, nation_nm = EXCLUDED.nation_nm, facility_size_overview = EXCLUDED.facility_size_overview;
|
||||
`;
|
||||
|
||||
const result = await client.query(queryString, values);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: '200',
|
||||
data: result.rows,
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
res.status(500).json({ success: false, message: '파일 업로드 중 오류가 발생했습니다.' });
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
}
|
||||
|
||||
exports.saveSectionMiddleData = async (req, res, next) => {
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
let {projectId, abbreviatedName, taskNmKr, taskNmEn, taskPurpose, orderSizeUsd, orderSizeKrw, scheduledCommencementDate, contractPeriod, clientOrigin, financial, financialCountry, selectionMethod, projectManagerNm, managerNm, supportDepartment, supportManagerNm, contractDate, commencementDate, originalCompletionDate, completionDate, projectNo, taskType, bid, relativeClient, department, jointContractComapnyName, jointContractShares, jointContractKrw, jointContractUsd, representativeCompany } = req.body;
|
||||
|
||||
let values = [projectId, abbreviatedName, taskNmKr, taskNmEn, taskPurpose, orderSizeUsd, orderSizeKrw, scheduledCommencementDate, contractPeriod, clientOrigin, financial, financialCountry, selectionMethod, projectManagerNm, managerNm, supportDepartment, supportManagerNm, contractDate, commencementDate, originalCompletionDate, completionDate, projectNo, taskType, bid, relativeClient, department, jointContractComapnyName, jointContractShares, jointContractKrw, jointContractUsd, representativeCompany];
|
||||
|
||||
let queryString = `
|
||||
INSERT INTO ver4.tb_overview (
|
||||
project_id, abbreviated_name, task_nm_kr, task_nm_en, task_purpose,
|
||||
order_size_usd, order_size_krw, scheuled_commencement_date, contract_period,
|
||||
client_origin, financial, financial_country, selection_method,
|
||||
projectmanager_nm, manager_nm, support_department, support_manager_nm,
|
||||
contract_date, commencement_date, original_completion_date, completion_date,
|
||||
project_no, task_type, bid, client, department,
|
||||
joint_contract_nm, joint_contract_shareratio, contract_amount, foreign_currency_amount, representative_company
|
||||
) VALUES (
|
||||
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27, $28, $29, $30, $31
|
||||
)
|
||||
ON CONFLICT (project_id)
|
||||
DO UPDATE SET
|
||||
abbreviated_name = EXCLUDED.abbreviated_name,
|
||||
task_nm_kr = EXCLUDED.task_nm_kr,
|
||||
task_nm_en = EXCLUDED.task_nm_en,
|
||||
task_purpose = EXCLUDED.task_purpose,
|
||||
order_size_usd = EXCLUDED.order_size_usd,
|
||||
order_size_krw = EXCLUDED.order_size_krw,
|
||||
scheuled_commencement_date = EXCLUDED.scheuled_commencement_date,
|
||||
contract_period = EXCLUDED.contract_period,
|
||||
client_origin = EXCLUDED.client_origin,
|
||||
financial = EXCLUDED.financial,
|
||||
financial_country = EXCLUDED.financial_country,
|
||||
selection_method = EXCLUDED.selection_method,
|
||||
projectmanager_nm = EXCLUDED.projectmanager_nm,
|
||||
manager_nm = EXCLUDED.manager_nm,
|
||||
support_department = EXCLUDED.support_department,
|
||||
support_manager_nm = EXCLUDED.support_manager_nm,
|
||||
contract_date = EXCLUDED.contract_date,
|
||||
commencement_date = EXCLUDED.commencement_date,
|
||||
original_completion_date = EXCLUDED.original_completion_date,
|
||||
completion_date = EXCLUDED.completion_date,
|
||||
project_no = EXCLUDED.project_no,
|
||||
task_type = EXCLUDED.task_type,
|
||||
bid = EXCLUDED.bid,
|
||||
client = EXCLUDED.client,
|
||||
department = EXCLUDED.department,
|
||||
joint_contract_nm = EXCLUDED.joint_contract_nm,
|
||||
joint_contract_shareratio = EXCLUDED.joint_contract_shareratio,
|
||||
contract_amount = EXCLUDED.contract_amount,
|
||||
foreign_currency_amount = EXCLUDED.foreign_currency_amount,
|
||||
representative_company = EXCLUDED.representative_company;
|
||||
`
|
||||
|
||||
const result = await client.query(queryString, values);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: '200',
|
||||
data: result.rows,
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
res.status(500).json({ success: false, message: 'section2 Save Data Error' });
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
};
|
||||
|
||||
exports.saveTaskHistoryData = async (req, res, next) => {
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
for (let i = 0; i < req.body.length; i++) {
|
||||
let { projectId, order, suspensionDate, suspensionReason, resumptionDate, consultationContent, changeDate } = req.body[i];
|
||||
|
||||
let queryString = `
|
||||
INSERT INTO ver4.tb_task_history (project_id, task_order, suspension_date, suspension_reason, resumption_date, consultation_content, change_date)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7);
|
||||
`
|
||||
|
||||
await client.query(queryString, [projectId, order, suspensionDate, suspensionReason, resumptionDate, consultationContent, changeDate]);
|
||||
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: '200',
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
res.status(500).json({ success: false, message: 'task history Save Data Error' });
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
exports.saveSectionLeftTabData = async (req, res, next) => {
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
const sections = req.body;
|
||||
|
||||
for (const title of Object.keys(sections)) {
|
||||
const rows = sections[title];
|
||||
|
||||
for (let i = 0; i < rows.length; i++) {
|
||||
const { key, value, id, projectId } = rows[i];
|
||||
|
||||
if (id == null || id === '') {
|
||||
const queryStringInsert = `
|
||||
INSERT INTO ver4.tb_facility_size (project_id, key, value, title)
|
||||
VALUES ($1, $2, $3 , $4)
|
||||
ON CONFLICT (facility_id)
|
||||
DO UPDATE SET project_id = EXCLUDED.project_id, key = EXCLUDED.key, value = EXCLUDED.value, title = EXCLUDED.title;
|
||||
`;
|
||||
await client.query(queryStringInsert, [projectId, key, value, title]);
|
||||
} else {
|
||||
const queryStringUpdate = `
|
||||
INSERT INTO ver4.tb_facility_size (project_id, key, value, facility_id, title)
|
||||
VALUES ($1, $2, $3, $4, $5)
|
||||
ON CONFLICT (facility_id)
|
||||
DO UPDATE SET project_id = EXCLUDED.project_id, key = EXCLUDED.key, value = EXCLUDED.value, title = EXCLUDED.title;
|
||||
`;
|
||||
await client.query(queryStringUpdate, [projectId, key, value, id, title]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res.json({ success: true, message: '200', });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
res.status(500).json({ success: false, message: 'FacilitySize Save Data Error' });
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
};
|
||||
|
||||
exports.saveIssueData = async (req, res, next) => {
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
|
||||
let { projectId, issueData } = req.body;
|
||||
|
||||
let queryString = `
|
||||
INSERT INTO ver4.tb_overview (
|
||||
project_id, issue
|
||||
) VALUES (
|
||||
$1, $2
|
||||
)
|
||||
ON CONFLICT (project_id)
|
||||
DO UPDATE SET
|
||||
issue = EXCLUDED.issue
|
||||
`
|
||||
|
||||
const result = await client.query(queryString, [projectId, issueData]);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: '200',
|
||||
data: result.rows,
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
res.status(500).json({ success: false, message: 'Save Issue Data Error' });
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
};
|
||||
|
||||
exports.generateUploadImgUrl = async (req,res,next) => {
|
||||
const projectId = req.baseUrl.split('/')[1];
|
||||
let {fileName} = req.body;
|
||||
|
||||
let bucket = projectId;
|
||||
let key = 'overview/' + fileName;
|
||||
try{
|
||||
// s3 명렁어 구성
|
||||
const command = new PutObjectCommand({
|
||||
Bucket: bucket,
|
||||
Key: key,
|
||||
ContentType: 'application/octet-stream'
|
||||
});
|
||||
|
||||
// presigned url 생성
|
||||
const url = await getSignedUrl(s3, command, { expiresIn: 60 * 5});
|
||||
// 클라이언트에 return
|
||||
res.json({ url, key });
|
||||
}catch(error){
|
||||
console.error('UploadPresigned URL 생성 실패: ', error);
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
exports.generateGetImgUrl = async (req,res,next) => {
|
||||
const projectId = req.baseUrl.split('/')[1];
|
||||
let { key } = req.query;
|
||||
let bucket = projectId;
|
||||
try{
|
||||
// s3 명렁어 구성
|
||||
const command = new GetObjectCommand({
|
||||
Bucket : bucket,
|
||||
Key : key
|
||||
});
|
||||
|
||||
const url = await getSignedUrl(s3, command, {expiresIn: 60});
|
||||
|
||||
res.json({ url });
|
||||
} catch(error){
|
||||
console.error('GetPresigned URL 생성 실패: ',error);
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
|
||||
exports.generateDeleteImgUrl = async (req, res, next) => {
|
||||
const projectId = req.baseUrl.split('/')[1];
|
||||
let { key } = req.body;
|
||||
let bucket = projectId;
|
||||
try{
|
||||
// s3 명령어 구성
|
||||
const command = new DeleteObjectCommand({
|
||||
Bucket : bucket,
|
||||
Key : key
|
||||
});
|
||||
|
||||
const url = await getSignedUrl(s3, command, {expiresIn: 60});
|
||||
|
||||
res.json({ url });
|
||||
} catch(error) {
|
||||
console.error('DeletePresigned URL 생성 실패: ',error);
|
||||
next(error)
|
||||
}
|
||||
}
|
||||
|
||||
exports.updateOverviewImgData = async (req, res) => {
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
let { projectId, locationImgKey, originFileSize } = req.body;
|
||||
let queryString = `
|
||||
UPDATE ver4.tb_overview
|
||||
SET location_img = $2, data_size = $3
|
||||
WHERE project_id = $1;
|
||||
`;
|
||||
const result = await client.query(queryString, [projectId, locationImgKey, originFileSize]);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: '200',
|
||||
data: result.rows,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('updateLocationImgData error: ', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: '500',
|
||||
error: error.message,
|
||||
});
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user