Raw SQL을 Prisma ORM으로 마이그레이션
This commit is contained in:
parent
bde5f0884a
commit
b365969c72
File diff suppressed because it is too large
Load Diff
|
|
@ -662,61 +662,53 @@ export async function getLangKeyList(
|
||||||
user: req.user,
|
user: req.user,
|
||||||
});
|
});
|
||||||
|
|
||||||
// 실제 데이터베이스에서 데이터 조회
|
// Prisma ORM을 사용한 다국어 키 목록 조회
|
||||||
const client = new Client({
|
const result = await prisma.multi_lang_key_master.findMany({
|
||||||
host: process.env.DB_HOST || "localhost",
|
orderBy: [
|
||||||
port: parseInt(process.env.DB_PORT || "5432"),
|
{ company_code: "asc" },
|
||||||
database: process.env.DB_NAME || "ilshin",
|
{ menu_name: "asc" },
|
||||||
user: process.env.DB_USER || "postgres",
|
{ lang_key: "asc" },
|
||||||
password: process.env.DB_PASSWORD || "postgres",
|
],
|
||||||
|
select: {
|
||||||
|
key_id: true,
|
||||||
|
company_code: true,
|
||||||
|
menu_name: true,
|
||||||
|
lang_key: true,
|
||||||
|
description: true,
|
||||||
|
is_active: true,
|
||||||
|
created_date: true,
|
||||||
|
created_by: true,
|
||||||
|
updated_date: true,
|
||||||
|
updated_by: true,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
await client.connect();
|
const langKeys = result.map((row) => ({
|
||||||
|
keyId: row.key_id,
|
||||||
|
companyCode: row.company_code,
|
||||||
|
menuName: row.menu_name,
|
||||||
|
langKey: row.lang_key,
|
||||||
|
description: row.description,
|
||||||
|
isActive: row.is_active,
|
||||||
|
createdDate: row.created_date?.toISOString(),
|
||||||
|
createdBy: row.created_by,
|
||||||
|
updatedDate: row.updated_date?.toISOString(),
|
||||||
|
updatedBy: row.updated_by,
|
||||||
|
}));
|
||||||
|
|
||||||
try {
|
// 프론트엔드에서 기대하는 응답 형식으로 변환
|
||||||
const query = `
|
const response: ApiResponse<any[]> = {
|
||||||
SELECT
|
success: true,
|
||||||
key_id as "keyId",
|
message: "다국어 키 목록 조회 성공",
|
||||||
company_code as "companyCode",
|
data: langKeys,
|
||||||
menu_name as "menuName",
|
};
|
||||||
lang_key as "langKey",
|
|
||||||
description,
|
|
||||||
is_active as "isActive",
|
|
||||||
created_date as "createdDate",
|
|
||||||
created_by as "createdBy",
|
|
||||||
updated_date as "updatedDate",
|
|
||||||
updated_by as "updatedBy"
|
|
||||||
FROM multi_lang_key_master
|
|
||||||
ORDER BY company_code, menu_name, lang_key
|
|
||||||
`;
|
|
||||||
|
|
||||||
const result = await client.query(query);
|
logger.info("다국어 키 목록 조회 성공", {
|
||||||
const langKeys = result.rows.map((row) => ({
|
totalCount: langKeys.length,
|
||||||
...row,
|
response: response,
|
||||||
createdDate: row.createdDate
|
});
|
||||||
? new Date(row.createdDate).toISOString()
|
|
||||||
: undefined,
|
|
||||||
updatedDate: row.updatedDate
|
|
||||||
? new Date(row.updatedDate).toISOString()
|
|
||||||
: undefined,
|
|
||||||
}));
|
|
||||||
|
|
||||||
// 프론트엔드에서 기대하는 응답 형식으로 변환
|
res.status(200).json(response);
|
||||||
const response: ApiResponse<any[]> = {
|
|
||||||
success: true,
|
|
||||||
message: "다국어 키 목록 조회 성공",
|
|
||||||
data: langKeys,
|
|
||||||
};
|
|
||||||
|
|
||||||
logger.info("다국어 키 목록 조회 성공", {
|
|
||||||
totalCount: langKeys.length,
|
|
||||||
response: response,
|
|
||||||
});
|
|
||||||
|
|
||||||
res.status(200).json(response);
|
|
||||||
} finally {
|
|
||||||
await client.end();
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error("다국어 키 목록 조회 실패:", error);
|
logger.error("다국어 키 목록 조회 실패:", error);
|
||||||
res.status(500).json({
|
res.status(500).json({
|
||||||
|
|
@ -1026,56 +1018,36 @@ export async function saveMenu(
|
||||||
const menuData = req.body;
|
const menuData = req.body;
|
||||||
logger.info("메뉴 저장 요청", { menuData, user: req.user });
|
logger.info("메뉴 저장 요청", { menuData, user: req.user });
|
||||||
|
|
||||||
// PostgreSQL 클라이언트 생성
|
// Prisma ORM을 사용한 메뉴 저장
|
||||||
const client = new Client({
|
const savedMenu = await prisma.menu_info.create({
|
||||||
connectionString:
|
data: {
|
||||||
process.env.DATABASE_URL ||
|
objid: Date.now(), // 고유 ID 생성
|
||||||
"postgresql://postgres:postgres@localhost:5432/ilshin",
|
menu_type: menuData.menuType ? Number(menuData.menuType) : null,
|
||||||
|
parent_obj_id: menuData.parentObjId
|
||||||
|
? Number(menuData.parentObjId)
|
||||||
|
: null,
|
||||||
|
menu_name_kor: menuData.menuNameKor,
|
||||||
|
menu_name_eng: menuData.menuNameEng || null,
|
||||||
|
seq: menuData.seq ? Number(menuData.seq) : null,
|
||||||
|
menu_url: menuData.menuUrl || null,
|
||||||
|
menu_desc: menuData.menuDesc || null,
|
||||||
|
writer: req.user?.userId || "admin",
|
||||||
|
regdate: new Date(),
|
||||||
|
status: menuData.status || "active",
|
||||||
|
system_name: menuData.systemName || "PLM",
|
||||||
|
company_code: menuData.companyCode || "*",
|
||||||
|
lang_key: menuData.langKey || null,
|
||||||
|
lang_key_desc: menuData.langKeyDesc || null,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
await client.connect();
|
|
||||||
|
|
||||||
// 실제 데이터베이스에 저장
|
|
||||||
const query = `
|
|
||||||
INSERT INTO menu_info (
|
|
||||||
objid, menu_type, parent_obj_id, menu_name_kor, menu_name_eng,
|
|
||||||
seq, menu_url, menu_desc, writer, regdate, status,
|
|
||||||
system_name, company_code, lang_key, lang_key_desc
|
|
||||||
) VALUES (
|
|
||||||
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15
|
|
||||||
) RETURNING *
|
|
||||||
`;
|
|
||||||
|
|
||||||
const values = [
|
|
||||||
Date.now(), // objid
|
|
||||||
menuData.menuType || null, // menu_type
|
|
||||||
menuData.parentObjId || null, // parent_obj_id
|
|
||||||
menuData.menuNameKor, // menu_name_kor
|
|
||||||
menuData.menuNameEng || null, // menu_name_eng
|
|
||||||
menuData.seq || null, // seq
|
|
||||||
menuData.menuUrl || null, // menu_url
|
|
||||||
menuData.menuDesc || null, // menu_desc
|
|
||||||
req.user?.userId || "admin", // writer
|
|
||||||
new Date(), // regdate
|
|
||||||
menuData.status || "active", // status
|
|
||||||
menuData.systemName || "PLM", // system_name
|
|
||||||
menuData.companyCode || "*", // company_code
|
|
||||||
menuData.langKey || null, // lang_key
|
|
||||||
menuData.langKeyDesc || null, // lang_key_desc
|
|
||||||
];
|
|
||||||
|
|
||||||
const result = await client.query(query, values);
|
|
||||||
const savedMenu = result.rows[0];
|
|
||||||
|
|
||||||
await client.end();
|
|
||||||
|
|
||||||
logger.info("메뉴 저장 성공", { savedMenu });
|
logger.info("메뉴 저장 성공", { savedMenu });
|
||||||
|
|
||||||
const response: ApiResponse<any> = {
|
const response: ApiResponse<any> = {
|
||||||
success: true,
|
success: true,
|
||||||
message: "메뉴가 성공적으로 저장되었습니다.",
|
message: "메뉴가 성공적으로 저장되었습니다.",
|
||||||
data: {
|
data: {
|
||||||
objid: savedMenu.objid,
|
objid: savedMenu.objid.toString(), // BigInt를 문자열로 변환
|
||||||
menuNameKor: savedMenu.menu_name_kor,
|
menuNameKor: savedMenu.menu_name_kor,
|
||||||
menuNameEng: savedMenu.menu_name_eng,
|
menuNameEng: savedMenu.menu_name_eng,
|
||||||
menuUrl: savedMenu.menu_url,
|
menuUrl: savedMenu.menu_url,
|
||||||
|
|
@ -1112,65 +1084,29 @@ export async function updateMenu(
|
||||||
user: req.user,
|
user: req.user,
|
||||||
});
|
});
|
||||||
|
|
||||||
// PostgreSQL 클라이언트 생성
|
// Prisma ORM을 사용한 메뉴 수정
|
||||||
const client = new Client({
|
const updatedMenu = await prisma.menu_info.update({
|
||||||
connectionString:
|
where: {
|
||||||
process.env.DATABASE_URL ||
|
objid: Number(menuId),
|
||||||
"postgresql://postgres:postgres@localhost:5432/ilshin",
|
},
|
||||||
|
data: {
|
||||||
|
menu_type: menuData.menuType ? Number(menuData.menuType) : null,
|
||||||
|
parent_obj_id: menuData.parentObjId
|
||||||
|
? Number(menuData.parentObjId)
|
||||||
|
: null,
|
||||||
|
menu_name_kor: menuData.menuNameKor,
|
||||||
|
menu_name_eng: menuData.menuNameEng || null,
|
||||||
|
seq: menuData.seq ? Number(menuData.seq) : null,
|
||||||
|
menu_url: menuData.menuUrl || null,
|
||||||
|
menu_desc: menuData.menuDesc || null,
|
||||||
|
status: menuData.status || "active",
|
||||||
|
system_name: menuData.systemName || "PLM",
|
||||||
|
company_code: menuData.companyCode || "*",
|
||||||
|
lang_key: menuData.langKey || null,
|
||||||
|
lang_key_desc: menuData.langKeyDesc || null,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
await client.connect();
|
|
||||||
|
|
||||||
// 실제 데이터베이스에서 메뉴 수정
|
|
||||||
const query = `
|
|
||||||
UPDATE menu_info
|
|
||||||
SET
|
|
||||||
menu_type = $1,
|
|
||||||
parent_obj_id = $2,
|
|
||||||
menu_name_kor = $3,
|
|
||||||
menu_name_eng = $4,
|
|
||||||
seq = $5,
|
|
||||||
menu_url = $6,
|
|
||||||
menu_desc = $7,
|
|
||||||
status = $8,
|
|
||||||
system_name = $9,
|
|
||||||
company_code = $10,
|
|
||||||
lang_key = $11,
|
|
||||||
lang_key_desc = $12
|
|
||||||
WHERE objid = $13
|
|
||||||
RETURNING *
|
|
||||||
`;
|
|
||||||
|
|
||||||
const values = [
|
|
||||||
menuData.menuType ? BigInt(menuData.menuType) : null, // menu_type
|
|
||||||
menuData.parentObjId ? BigInt(menuData.parentObjId) : null, // parent_obj_id
|
|
||||||
menuData.menuNameKor, // menu_name_kor
|
|
||||||
menuData.menuNameEng || null, // menu_name_eng
|
|
||||||
menuData.seq ? BigInt(menuData.seq) : null, // seq
|
|
||||||
menuData.menuUrl || null, // menu_url
|
|
||||||
menuData.menuDesc || null, // menu_desc
|
|
||||||
menuData.status || "active", // status
|
|
||||||
menuData.systemName || "PLM", // system_name
|
|
||||||
menuData.companyCode || "*", // company_code
|
|
||||||
menuData.langKey || null, // lang_key
|
|
||||||
menuData.langKeyDesc || null, // lang_key_desc
|
|
||||||
BigInt(menuId), // objid (WHERE 조건)
|
|
||||||
];
|
|
||||||
|
|
||||||
const result = await client.query(query, values);
|
|
||||||
|
|
||||||
if (result.rowCount === 0) {
|
|
||||||
await client.end();
|
|
||||||
res.status(404).json({
|
|
||||||
success: false,
|
|
||||||
message: "수정할 메뉴를 찾을 수 없습니다.",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const updatedMenu = result.rows[0];
|
|
||||||
await client.end();
|
|
||||||
|
|
||||||
logger.info("메뉴 수정 성공", { updatedMenu });
|
logger.info("메뉴 수정 성공", { updatedMenu });
|
||||||
|
|
||||||
const response: ApiResponse<any> = {
|
const response: ApiResponse<any> = {
|
||||||
|
|
@ -1210,36 +1146,13 @@ export async function deleteMenu(
|
||||||
const { menuId } = req.params;
|
const { menuId } = req.params;
|
||||||
logger.info(`메뉴 삭제 요청: menuId = ${menuId}`, { user: req.user });
|
logger.info(`메뉴 삭제 요청: menuId = ${menuId}`, { user: req.user });
|
||||||
|
|
||||||
// PostgreSQL 클라이언트 생성
|
// Prisma ORM을 사용한 메뉴 삭제
|
||||||
const client = new Client({
|
const deletedMenu = await prisma.menu_info.delete({
|
||||||
connectionString:
|
where: {
|
||||||
process.env.DATABASE_URL ||
|
objid: Number(menuId),
|
||||||
"postgresql://postgres:postgres@localhost:5432/ilshin",
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
await client.connect();
|
|
||||||
|
|
||||||
// 실제 데이터베이스에서 메뉴 삭제
|
|
||||||
const query = `
|
|
||||||
DELETE FROM menu_info
|
|
||||||
WHERE objid = $1
|
|
||||||
RETURNING *
|
|
||||||
`;
|
|
||||||
|
|
||||||
const result = await client.query(query, [BigInt(menuId)]);
|
|
||||||
|
|
||||||
if (result.rowCount === 0) {
|
|
||||||
await client.end();
|
|
||||||
res.status(404).json({
|
|
||||||
success: false,
|
|
||||||
message: "삭제할 메뉴를 찾을 수 없습니다.",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const deletedMenu = result.rows[0];
|
|
||||||
await client.end();
|
|
||||||
|
|
||||||
logger.info("메뉴 삭제 성공", { deletedMenu });
|
logger.info("메뉴 삭제 성공", { deletedMenu });
|
||||||
|
|
||||||
const response: ApiResponse<any> = {
|
const response: ApiResponse<any> = {
|
||||||
|
|
@ -1287,15 +1200,7 @@ export async function deleteMenusBatch(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// PostgreSQL 클라이언트 생성
|
// Prisma ORM을 사용한 메뉴 일괄 삭제
|
||||||
const client = new Client({
|
|
||||||
connectionString:
|
|
||||||
process.env.DATABASE_URL ||
|
|
||||||
"postgresql://postgres:postgres@localhost:5432/ilshin",
|
|
||||||
});
|
|
||||||
|
|
||||||
await client.connect();
|
|
||||||
|
|
||||||
let deletedCount = 0;
|
let deletedCount = 0;
|
||||||
let failedCount = 0;
|
let failedCount = 0;
|
||||||
const deletedMenus: any[] = [];
|
const deletedMenus: any[] = [];
|
||||||
|
|
@ -1304,17 +1209,18 @@ export async function deleteMenusBatch(
|
||||||
// 각 메뉴 ID에 대해 삭제 시도
|
// 각 메뉴 ID에 대해 삭제 시도
|
||||||
for (const menuId of menuIds) {
|
for (const menuId of menuIds) {
|
||||||
try {
|
try {
|
||||||
const query = `
|
const deletedMenu = await prisma.menu_info.delete({
|
||||||
DELETE FROM menu_info
|
where: {
|
||||||
WHERE objid = $1
|
objid: Number(menuId),
|
||||||
RETURNING *
|
},
|
||||||
`;
|
});
|
||||||
|
|
||||||
const result = await client.query(query, [BigInt(menuId)]);
|
if (deletedMenu) {
|
||||||
|
|
||||||
if (result.rowCount && result.rowCount > 0) {
|
|
||||||
deletedCount++;
|
deletedCount++;
|
||||||
deletedMenus.push(result.rows[0]);
|
deletedMenus.push({
|
||||||
|
...deletedMenu,
|
||||||
|
objid: deletedMenu.objid.toString(),
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
failedCount++;
|
failedCount++;
|
||||||
failedMenuIds.push(menuId);
|
failedMenuIds.push(menuId);
|
||||||
|
|
@ -1326,8 +1232,6 @@ export async function deleteMenusBatch(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await client.end();
|
|
||||||
|
|
||||||
logger.info("메뉴 일괄 삭제 완료", {
|
logger.info("메뉴 일괄 삭제 완료", {
|
||||||
total: menuIds.length,
|
total: menuIds.length,
|
||||||
deletedCount,
|
deletedCount,
|
||||||
|
|
@ -1561,125 +1465,94 @@ export const getUserInfo = async (req: AuthenticatedRequest, res: Response) => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// PostgreSQL 클라이언트 생성
|
// Prisma ORM을 사용한 사용자 상세 정보 조회
|
||||||
const client = new Client({
|
const user = await prisma.user_info.findUnique({
|
||||||
connectionString:
|
where: {
|
||||||
process.env.DATABASE_URL ||
|
user_id: userId,
|
||||||
"postgresql://postgres:postgres@localhost:5432/ilshin",
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
await client.connect();
|
if (!user) {
|
||||||
|
res.status(404).json({
|
||||||
try {
|
success: false,
|
||||||
// 사용자 상세 정보 조회 쿼리
|
message: "사용자를 찾을 수 없습니다.",
|
||||||
const query = `
|
error: {
|
||||||
SELECT
|
code: "USER_NOT_FOUND",
|
||||||
u.sabun,
|
details: `User ID: ${userId}`,
|
||||||
u.user_id,
|
|
||||||
u.user_name,
|
|
||||||
u.user_name_eng,
|
|
||||||
u.user_name_cn,
|
|
||||||
u.dept_code,
|
|
||||||
u.dept_name,
|
|
||||||
u.position_code,
|
|
||||||
u.position_name,
|
|
||||||
u.email,
|
|
||||||
u.tel,
|
|
||||||
u.cell_phone,
|
|
||||||
u.user_type,
|
|
||||||
u.user_type_name,
|
|
||||||
u.regdate,
|
|
||||||
u.status,
|
|
||||||
u.end_date,
|
|
||||||
u.fax_no,
|
|
||||||
u.partner_objid,
|
|
||||||
u.rank,
|
|
||||||
u.photo,
|
|
||||||
u.locale,
|
|
||||||
u.company_code,
|
|
||||||
u.data_type,
|
|
||||||
d.dept_name as dept_name_full,
|
|
||||||
d.parent_dept_code,
|
|
||||||
d.location,
|
|
||||||
d.location_name,
|
|
||||||
d.sales_yn,
|
|
||||||
d.company_name as dept_company_name
|
|
||||||
FROM user_info u
|
|
||||||
LEFT JOIN dept_info d ON u.dept_code = d.dept_code
|
|
||||||
WHERE u.user_id = $1
|
|
||||||
`;
|
|
||||||
|
|
||||||
const result = await client.query(query, [userId]);
|
|
||||||
|
|
||||||
if (result.rows.length === 0) {
|
|
||||||
res.status(404).json({
|
|
||||||
success: false,
|
|
||||||
message: "사용자를 찾을 수 없습니다.",
|
|
||||||
error: {
|
|
||||||
code: "USER_NOT_FOUND",
|
|
||||||
details: `User ID: ${userId}`,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const user = result.rows[0];
|
|
||||||
|
|
||||||
// 응답 데이터 가공
|
|
||||||
const userInfo = {
|
|
||||||
sabun: user.sabun,
|
|
||||||
userId: user.user_id,
|
|
||||||
userName: user.user_name,
|
|
||||||
userNameEng: user.user_name_eng,
|
|
||||||
userNameCn: user.user_name_cn,
|
|
||||||
deptCode: user.dept_code,
|
|
||||||
deptName: user.dept_name || user.dept_name_full,
|
|
||||||
positionCode: user.position_code,
|
|
||||||
positionName: user.position_name,
|
|
||||||
email: user.email,
|
|
||||||
tel: user.tel,
|
|
||||||
cellPhone: user.cell_phone,
|
|
||||||
userType: user.user_type,
|
|
||||||
userTypeName: user.user_type_name,
|
|
||||||
regdate: user.regdate ? user.regdate.toISOString() : null,
|
|
||||||
status: user.status || "active",
|
|
||||||
endDate: user.end_date ? user.end_date.toISOString() : null,
|
|
||||||
faxNo: user.fax_no,
|
|
||||||
partnerObjid: user.partner_objid,
|
|
||||||
rank: user.rank,
|
|
||||||
photo: user.photo
|
|
||||||
? `data:image/jpeg;base64,${user.photo.toString("base64")}`
|
|
||||||
: null,
|
|
||||||
locale: user.locale,
|
|
||||||
companyCode: user.company_code,
|
|
||||||
dataType: user.data_type,
|
|
||||||
// 부서 정보
|
|
||||||
deptInfo: {
|
|
||||||
deptCode: user.dept_code,
|
|
||||||
deptName: user.dept_name || user.dept_name_full,
|
|
||||||
parentDeptCode: user.parent_dept_code,
|
|
||||||
location: user.location,
|
|
||||||
locationName: user.location_name,
|
|
||||||
salesYn: user.sales_yn,
|
|
||||||
companyName: user.dept_company_name,
|
|
||||||
},
|
},
|
||||||
};
|
|
||||||
|
|
||||||
const response = {
|
|
||||||
success: true,
|
|
||||||
data: userInfo,
|
|
||||||
message: "사용자 상세 정보 조회 성공",
|
|
||||||
};
|
|
||||||
|
|
||||||
logger.info("사용자 상세 정보 조회 성공", {
|
|
||||||
userId,
|
|
||||||
userName: user.user_name,
|
|
||||||
});
|
});
|
||||||
|
return;
|
||||||
res.status(200).json(response);
|
|
||||||
} finally {
|
|
||||||
await client.end();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 부서 정보 별도 조회
|
||||||
|
const deptInfo = user.dept_code
|
||||||
|
? await prisma.dept_info.findUnique({
|
||||||
|
where: {
|
||||||
|
dept_code: user.dept_code,
|
||||||
|
},
|
||||||
|
select: {
|
||||||
|
dept_name: true,
|
||||||
|
parent_dept_code: true,
|
||||||
|
location: true,
|
||||||
|
location_name: true,
|
||||||
|
sales_yn: true,
|
||||||
|
company_name: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
: null;
|
||||||
|
|
||||||
|
// 응답 데이터 가공
|
||||||
|
const userInfo = {
|
||||||
|
sabun: user.sabun,
|
||||||
|
userId: user.user_id,
|
||||||
|
userName: user.user_name,
|
||||||
|
userNameEng: user.user_name_eng,
|
||||||
|
userNameCn: user.user_name_cn,
|
||||||
|
deptCode: user.dept_code,
|
||||||
|
deptName: user.dept_name,
|
||||||
|
positionCode: user.position_code,
|
||||||
|
positionName: user.position_name,
|
||||||
|
email: user.email,
|
||||||
|
tel: user.tel,
|
||||||
|
cellPhone: user.cell_phone,
|
||||||
|
userType: user.user_type,
|
||||||
|
userTypeName: user.user_type_name,
|
||||||
|
regdate: user.regdate ? user.regdate.toISOString() : null,
|
||||||
|
status: user.status || "active",
|
||||||
|
endDate: user.end_date ? user.end_date.toISOString() : null,
|
||||||
|
faxNo: user.fax_no,
|
||||||
|
partnerObjid: user.partner_objid,
|
||||||
|
rank: user.rank,
|
||||||
|
photo: user.photo
|
||||||
|
? `data:image/jpeg;base64,${user.photo.toString("base64")}`
|
||||||
|
: null,
|
||||||
|
locale: user.locale,
|
||||||
|
companyCode: user.company_code,
|
||||||
|
dataType: user.data_type,
|
||||||
|
// 부서 정보
|
||||||
|
deptInfo: {
|
||||||
|
deptCode: user.dept_code,
|
||||||
|
deptName: deptInfo?.dept_name,
|
||||||
|
parentDeptCode: deptInfo?.parent_dept_code,
|
||||||
|
location: deptInfo?.location,
|
||||||
|
locationName: deptInfo?.location_name,
|
||||||
|
salesYn: deptInfo?.sales_yn,
|
||||||
|
companyName: deptInfo?.company_name,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const response = {
|
||||||
|
success: true,
|
||||||
|
data: userInfo,
|
||||||
|
message: "사용자 상세 정보 조회 성공",
|
||||||
|
};
|
||||||
|
|
||||||
|
logger.info("사용자 상세 정보 조회 성공", {
|
||||||
|
userId,
|
||||||
|
userName: user.user_name,
|
||||||
|
});
|
||||||
|
|
||||||
|
res.status(200).json(response);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error("사용자 상세 정보 조회 실패", {
|
logger.error("사용자 상세 정보 조회 실패", {
|
||||||
error,
|
error,
|
||||||
|
|
@ -1955,98 +1828,66 @@ export const changeUserStatus = async (
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 복잡한 상태 변경은 직접 쿼리 사용
|
// Prisma ORM을 사용한 사용자 상태 변경
|
||||||
const client = new Client({
|
// 1. 사용자 존재 여부 확인
|
||||||
connectionString: config.databaseUrl,
|
const currentUser = await prisma.user_info.findUnique({
|
||||||
|
where: {
|
||||||
|
user_id: userId,
|
||||||
|
},
|
||||||
|
select: {
|
||||||
|
user_id: true,
|
||||||
|
user_name: true,
|
||||||
|
status: true,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
if (!currentUser) {
|
||||||
// 1. Prisma ORM으로 사용자 존재 여부 확인
|
res.status(404).json({
|
||||||
const currentUser = await prisma.user_info.findUnique({
|
result: false,
|
||||||
where: {
|
msg: "사용자를 찾을 수 없습니다.",
|
||||||
user_id: userId,
|
});
|
||||||
},
|
return;
|
||||||
select: {
|
}
|
||||||
user_id: true,
|
|
||||||
user_name: true,
|
// 2. 상태 변경 데이터 준비
|
||||||
status: true,
|
let updateData: any = {
|
||||||
},
|
status: status,
|
||||||
|
};
|
||||||
|
|
||||||
|
// active/inactive에 따른 END_DATE 처리
|
||||||
|
if (status === "inactive") {
|
||||||
|
updateData.end_date = new Date();
|
||||||
|
} else if (status === "active") {
|
||||||
|
updateData.end_date = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Prisma ORM으로 상태 변경 실행
|
||||||
|
const updateResult = await prisma.user_info.update({
|
||||||
|
where: {
|
||||||
|
user_id: userId,
|
||||||
|
},
|
||||||
|
data: updateData,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (updateResult) {
|
||||||
|
// 사용자 이력 저장은 user_info_history 테이블이 @@ignore 상태이므로 생략
|
||||||
|
|
||||||
|
logger.info("사용자 상태 변경 성공", {
|
||||||
|
userId,
|
||||||
|
oldStatus: currentUser.status,
|
||||||
|
newStatus: status,
|
||||||
|
updatedBy: req.user?.userId,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!currentUser) {
|
res.json({
|
||||||
res.status(404).json({
|
result: true,
|
||||||
result: false,
|
msg: `사용자 상태가 ${status === "active" ? "활성" : "비활성"}으로 변경되었습니다.`,
|
||||||
msg: "사용자를 찾을 수 없습니다.",
|
});
|
||||||
});
|
} else {
|
||||||
return;
|
res.status(400).json({
|
||||||
}
|
result: false,
|
||||||
|
msg: "사용자 상태 변경에 실패했습니다.",
|
||||||
await client.connect();
|
});
|
||||||
|
|
||||||
// 2. 상태 변경 쿼리 실행
|
|
||||||
let updateQuery = `
|
|
||||||
UPDATE user_info
|
|
||||||
SET status = $1
|
|
||||||
`;
|
|
||||||
|
|
||||||
const queryParams = [status];
|
|
||||||
|
|
||||||
// active/inactive에 따른 END_DATE 처리
|
|
||||||
if (status === "inactive") {
|
|
||||||
updateQuery += `, end_date = NOW()`;
|
|
||||||
} else if (status === "active") {
|
|
||||||
updateQuery += `, end_date = NULL`;
|
|
||||||
}
|
|
||||||
|
|
||||||
updateQuery += ` WHERE user_id = $2`;
|
|
||||||
queryParams.push(userId);
|
|
||||||
|
|
||||||
const updateResult = await client.query(updateQuery, queryParams);
|
|
||||||
|
|
||||||
if (updateResult.rowCount && updateResult.rowCount > 0) {
|
|
||||||
// 3. 사용자 이력 저장 (선택적)
|
|
||||||
try {
|
|
||||||
await client.query(
|
|
||||||
`
|
|
||||||
INSERT INTO user_info_history
|
|
||||||
(user_id, user_name, dept_code, dept_name, user_type_name, history_type, writer, reg_date, status, sabun)
|
|
||||||
VALUES ($1, $2, '', '', '', '사용자 상태 변경', $3, NOW(), $4, '')
|
|
||||||
`,
|
|
||||||
[
|
|
||||||
userId,
|
|
||||||
currentUser.user_name || userId,
|
|
||||||
req.user?.userId || "system",
|
|
||||||
status,
|
|
||||||
]
|
|
||||||
);
|
|
||||||
} catch (historyError) {
|
|
||||||
logger.warn("사용자 이력 저장 실패", {
|
|
||||||
error: historyError,
|
|
||||||
userId,
|
|
||||||
status,
|
|
||||||
});
|
|
||||||
// 이력 저장 실패는 치명적이지 않으므로 계속 진행
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.info("사용자 상태 변경 성공", {
|
|
||||||
userId,
|
|
||||||
oldStatus: currentUser.status,
|
|
||||||
newStatus: status,
|
|
||||||
updatedBy: req.user?.userId,
|
|
||||||
});
|
|
||||||
|
|
||||||
res.json({
|
|
||||||
result: true,
|
|
||||||
msg: `사용자 상태가 ${status === "active" ? "활성" : "비활성"}으로 변경되었습니다.`,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
res.status(400).json({
|
|
||||||
result: false,
|
|
||||||
msg: "사용자 상태 변경에 실패했습니다.",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
await client.end();
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error("사용자 상태 변경 중 오류 발생", {
|
logger.error("사용자 상태 변경 중 오류 발생", {
|
||||||
|
|
@ -2315,63 +2156,36 @@ export const updateCompany = async (
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// PostgreSQL 클라이언트 생성
|
// Prisma ORM으로 회사명 중복 체크 (자기 자신 제외)
|
||||||
const client = new Client({
|
const duplicateCompany = await prisma.company_mng.findFirst({
|
||||||
connectionString:
|
where: {
|
||||||
process.env.DATABASE_URL ||
|
company_name: company_name.trim(),
|
||||||
"postgresql://postgres:postgres@localhost:5432/ilshin",
|
company_code: {
|
||||||
|
not: companyCode,
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
await client.connect();
|
if (duplicateCompany) {
|
||||||
|
res.status(400).json({
|
||||||
|
success: false,
|
||||||
|
message: "이미 등록된 회사명입니다.",
|
||||||
|
errorCode: "COMPANY_NAME_DUPLICATE",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prisma ORM으로 회사 정보 수정
|
||||||
try {
|
try {
|
||||||
// 회사명 중복 체크 (자기 자신 제외)
|
const updatedCompany = await prisma.company_mng.update({
|
||||||
const duplicateCheckQuery = `
|
where: {
|
||||||
SELECT COUNT(*) as count
|
company_code: companyCode,
|
||||||
FROM company_mng
|
},
|
||||||
WHERE company_name = $1 AND company_code != $2
|
data: {
|
||||||
`;
|
company_name: company_name.trim(),
|
||||||
|
status: status || "active",
|
||||||
const duplicateResult = await client.query(duplicateCheckQuery, [
|
},
|
||||||
company_name.trim(),
|
});
|
||||||
companyCode,
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (parseInt(duplicateResult.rows[0].count) > 0) {
|
|
||||||
res.status(400).json({
|
|
||||||
success: false,
|
|
||||||
message: "이미 등록된 회사명입니다.",
|
|
||||||
errorCode: "COMPANY_NAME_DUPLICATE",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 회사 정보 수정
|
|
||||||
const updateQuery = `
|
|
||||||
UPDATE company_mng
|
|
||||||
SET company_name = $1, status = $2
|
|
||||||
WHERE company_code = $3
|
|
||||||
RETURNING *
|
|
||||||
`;
|
|
||||||
|
|
||||||
const updateValues = [
|
|
||||||
company_name.trim(),
|
|
||||||
status || "active",
|
|
||||||
companyCode,
|
|
||||||
];
|
|
||||||
|
|
||||||
const updateResult = await client.query(updateQuery, updateValues);
|
|
||||||
|
|
||||||
if (updateResult.rows.length === 0) {
|
|
||||||
res.status(404).json({
|
|
||||||
success: false,
|
|
||||||
message: "해당 회사를 찾을 수 없습니다.",
|
|
||||||
errorCode: "COMPANY_NOT_FOUND",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const updatedCompany = updateResult.rows[0];
|
|
||||||
|
|
||||||
logger.info("회사 정보 수정 성공", {
|
logger.info("회사 정보 수정 성공", {
|
||||||
companyCode: updatedCompany.company_code,
|
companyCode: updatedCompany.company_code,
|
||||||
|
|
@ -2392,8 +2206,17 @@ export const updateCompany = async (
|
||||||
};
|
};
|
||||||
|
|
||||||
res.status(200).json(response);
|
res.status(200).json(response);
|
||||||
} finally {
|
} catch (updateError: any) {
|
||||||
await client.end();
|
if (updateError.code === "P2025") {
|
||||||
|
// Prisma error code for "Record to update not found"
|
||||||
|
res.status(404).json({
|
||||||
|
success: false,
|
||||||
|
message: "해당 회사를 찾을 수 없습니다.",
|
||||||
|
errorCode: "COMPANY_NOT_FOUND",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw updateError;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error("회사 정보 수정 실패", { error, body: req.body });
|
logger.error("회사 정보 수정 실패", { error, body: req.body });
|
||||||
|
|
@ -2639,9 +2462,6 @@ export const resetUserPassword = async (
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 복잡한 암호화 로직은 직접 쿼리 사용
|
|
||||||
const client = new Client({ connectionString: config.databaseUrl });
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 1. Prisma ORM으로 사용자 존재 여부 확인
|
// 1. Prisma ORM으로 사용자 존재 여부 확인
|
||||||
const currentUser = await prisma.user_info.findUnique({
|
const currentUser = await prisma.user_info.findUnique({
|
||||||
|
|
@ -2664,8 +2484,6 @@ export const resetUserPassword = async (
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await client.connect();
|
|
||||||
|
|
||||||
// 2. 비밀번호 암호화 (기존 Java 로직과 동일)
|
// 2. 비밀번호 암호화 (기존 Java 로직과 동일)
|
||||||
let encryptedPassword: string;
|
let encryptedPassword: string;
|
||||||
try {
|
try {
|
||||||
|
|
@ -2693,31 +2511,18 @@ export const resetUserPassword = async (
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. 비밀번호 업데이트 실행
|
// 3. Prisma ORM으로 비밀번호 업데이트 실행
|
||||||
const updateResult = await client.query(
|
const updateResult = await prisma.user_info.update({
|
||||||
"UPDATE user_info SET user_password = $1 WHERE user_id = $2",
|
where: {
|
||||||
[encryptedPassword, userId]
|
user_id: userId,
|
||||||
);
|
},
|
||||||
|
data: {
|
||||||
|
user_password: encryptedPassword,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
if (updateResult.rowCount && updateResult.rowCount > 0) {
|
if (updateResult) {
|
||||||
// 4. 이력 저장 (선택적)
|
// 이력 저장은 user_info_history 테이블이 @@ignore 상태이므로 생략
|
||||||
try {
|
|
||||||
const writer = req.user?.userId || "system";
|
|
||||||
await client.query(
|
|
||||||
`
|
|
||||||
INSERT INTO user_info_history
|
|
||||||
(sabun, user_id, user_name, dept_code, dept_name, user_type_name, history_type, writer, regdate, status)
|
|
||||||
VALUES ('', $1, $2, '', '', '', '비밀번호 초기화', $3, NOW(), '')
|
|
||||||
`,
|
|
||||||
[userId, currentUser.user_name || userId, writer]
|
|
||||||
);
|
|
||||||
} catch (historyError) {
|
|
||||||
logger.warn("비밀번호 초기화 이력 저장 실패", {
|
|
||||||
error: historyError,
|
|
||||||
userId,
|
|
||||||
});
|
|
||||||
// 이력 저장 실패해도 비밀번호 초기화는 성공으로 처리
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.info("비밀번호 초기화 성공", {
|
logger.info("비밀번호 초기화 성공", {
|
||||||
userId,
|
userId,
|
||||||
|
|
@ -2749,7 +2554,5 @@ export const resetUserPassword = async (
|
||||||
message: "비밀번호 초기화 중 시스템 오류가 발생했습니다.",
|
message: "비밀번호 초기화 중 시스템 오류가 발생했습니다.",
|
||||||
msg: "비밀번호 초기화 중 시스템 오류가 발생했습니다.",
|
msg: "비밀번호 초기화 중 시스템 오류가 발생했습니다.",
|
||||||
});
|
});
|
||||||
} finally {
|
|
||||||
await client.end();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -333,23 +333,36 @@ export class AdminService {
|
||||||
try {
|
try {
|
||||||
logger.info(`AdminService.getMenuInfo 시작 - menuId: ${menuId}`);
|
logger.info(`AdminService.getMenuInfo 시작 - menuId: ${menuId}`);
|
||||||
|
|
||||||
// menu_info 모델이 @@ignore로 설정되어 있으므로 $queryRaw 사용
|
// Prisma ORM을 사용한 메뉴 정보 조회 (회사 정보 포함)
|
||||||
const menuInfo = await prisma.$queryRaw<any[]>`
|
const menuInfo = await prisma.menu_info.findUnique({
|
||||||
SELECT
|
where: {
|
||||||
MI.*,
|
objid: Number(menuId),
|
||||||
COALESCE(CM.COMPANY_NAME, '미지정') AS COMPANY_NAME
|
},
|
||||||
FROM MENU_INFO MI
|
include: {
|
||||||
LEFT JOIN COMPANY_MNG CM ON MI.COMPANY_CODE = CM.COMPANY_CODE
|
company: {
|
||||||
WHERE MI.OBJID = ${parseInt(menuId)}::numeric
|
select: {
|
||||||
LIMIT 1
|
company_name: true,
|
||||||
`;
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
if (!menuInfo || menuInfo.length === 0) {
|
if (!menuInfo) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info("메뉴 정보 조회 결과:", menuInfo[0]);
|
// 응답 형식 조정 (기존 형식과 호환성 유지)
|
||||||
return menuInfo[0];
|
const result = {
|
||||||
|
...menuInfo,
|
||||||
|
objid: menuInfo.objid.toString(), // BigInt를 문자열로 변환
|
||||||
|
menu_type: menuInfo.menu_type?.toString(),
|
||||||
|
parent_obj_id: menuInfo.parent_obj_id?.toString(),
|
||||||
|
seq: menuInfo.seq?.toString(),
|
||||||
|
company_name: menuInfo.company?.company_name || "미지정",
|
||||||
|
};
|
||||||
|
|
||||||
|
logger.info("메뉴 정보 조회 결과:", result);
|
||||||
|
return result;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error("AdminService.getMenuInfo 오류:", error);
|
logger.error("AdminService.getMenuInfo 오류:", error);
|
||||||
throw error;
|
throw error;
|
||||||
|
|
|
||||||
|
|
@ -155,23 +155,35 @@ export class AuthService {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 권한 정보 조회 (기존 Java 로직과 동일)
|
// 권한 정보 조회 (Prisma ORM 사용)
|
||||||
const authInfo = await prisma.$queryRaw<Array<{ auth_name: string }>>`
|
const authInfo = await prisma.authority_sub_user.findMany({
|
||||||
SELECT ARRAY_TO_STRING(ARRAY_AGG(AM.AUTH_NAME), ',') AS AUTH_NAME
|
where: {
|
||||||
FROM AUTHORITY_MASTER AM, AUTHORITY_SUB_USER ASU
|
user_id: userId,
|
||||||
WHERE AM.OBJID = ASU.MASTER_OBJID
|
},
|
||||||
AND ASU.USER_ID = ${userId}
|
include: {
|
||||||
GROUP BY ASU.USER_ID
|
authority_master: {
|
||||||
`;
|
select: {
|
||||||
|
auth_name: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
// 회사 정보 조회 (기존 Java 로직과 동일)
|
// 권한명들을 쉼표로 연결
|
||||||
const companyInfo = await prisma.$queryRaw<
|
const authNames = authInfo
|
||||||
Array<{ company_name: string }>
|
.filter((auth) => auth.authority_master?.auth_name)
|
||||||
>`
|
.map((auth) => auth.authority_master!.auth_name!)
|
||||||
SELECT COALESCE(CM.COMPANY_NAME, '미지정') AS COMPANY_NAME
|
.join(",");
|
||||||
FROM COMPANY_MNG CM
|
|
||||||
WHERE CM.COMPANY_CODE = ${userInfo.company_code || "ILSHIN"}
|
// 회사 정보 조회 (Prisma ORM 사용으로 변경)
|
||||||
`;
|
const companyInfo = await prisma.company_mng.findFirst({
|
||||||
|
where: {
|
||||||
|
company_code: userInfo.company_code || "ILSHIN",
|
||||||
|
},
|
||||||
|
select: {
|
||||||
|
company_name: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
// PersonBean 형태로 변환 (null 값을 undefined로 변환)
|
// PersonBean 형태로 변환 (null 값을 undefined로 변환)
|
||||||
const personBean: PersonBean = {
|
const personBean: PersonBean = {
|
||||||
|
|
@ -189,9 +201,11 @@ export class AuthService {
|
||||||
userType: userInfo.user_type || undefined,
|
userType: userInfo.user_type || undefined,
|
||||||
userTypeName: userInfo.user_type_name || undefined,
|
userTypeName: userInfo.user_type_name || undefined,
|
||||||
partnerObjid: userInfo.partner_objid || undefined,
|
partnerObjid: userInfo.partner_objid || undefined,
|
||||||
authName: authInfo.length > 0 ? authInfo[0].auth_name : undefined,
|
authName: authNames || undefined,
|
||||||
companyCode: userInfo.company_code || "ILSHIN",
|
companyCode: userInfo.company_code || "ILSHIN",
|
||||||
photo: userInfo.photo ? `data:image/jpeg;base64,${userInfo.photo.toString('base64')}` : undefined,
|
photo: userInfo.photo
|
||||||
|
? `data:image/jpeg;base64,${userInfo.photo.toString("base64")}`
|
||||||
|
: undefined,
|
||||||
locale: userInfo.locale || "KR",
|
locale: userInfo.locale || "KR",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue