초기 PM 소스 전체 업로드

This commit is contained in:
koj729
2026-06-12 17:14:03 +09:00
commit 4e33c9a02a
1769 changed files with 377797 additions and 0 deletions

View 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;
}