각 회사별 데이터 분리
This commit is contained in:
@@ -195,6 +195,8 @@ export const getUserList = async (req: AuthenticatedRequest, res: Response) => {
|
||||
search_email,
|
||||
deptCode,
|
||||
status,
|
||||
companyCode, // 회사 코드 필터 추가
|
||||
size, // countPerPage 대신 사용 가능
|
||||
} = req.query;
|
||||
|
||||
// Raw Query를 사용한 사용자 목록 조회
|
||||
@@ -203,6 +205,14 @@ export const getUserList = async (req: AuthenticatedRequest, res: Response) => {
|
||||
let queryParams: any[] = [];
|
||||
let paramIndex = 1;
|
||||
|
||||
// 회사 코드 필터 (권한 그룹 멤버 관리 시 사용)
|
||||
if (companyCode && typeof companyCode === "string" && companyCode.trim()) {
|
||||
whereConditions.push(`company_code = $${paramIndex}`);
|
||||
queryParams.push(companyCode.trim());
|
||||
paramIndex++;
|
||||
logger.info("회사 코드 필터 적용", { companyCode });
|
||||
}
|
||||
|
||||
// 검색 조건 처리
|
||||
if (search && typeof search === "string" && search.trim()) {
|
||||
// 통합 검색
|
||||
@@ -303,6 +313,16 @@ export const getUserList = async (req: AuthenticatedRequest, res: Response) => {
|
||||
}
|
||||
}
|
||||
|
||||
// 현재 로그인한 사용자의 회사 코드 필터 (슈퍼관리자가 아닌 경우)
|
||||
if (req.user && req.user.companyCode !== "*" && !companyCode) {
|
||||
whereConditions.push(`company_code = $${paramIndex}`);
|
||||
queryParams.push(req.user.companyCode);
|
||||
paramIndex++;
|
||||
logger.info("사용자 회사 코드 필터 적용", {
|
||||
companyCode: req.user.companyCode,
|
||||
});
|
||||
}
|
||||
|
||||
// 기존 필터들
|
||||
if (deptCode) {
|
||||
whereConditions.push(`dept_code = $${paramIndex}`);
|
||||
@@ -331,7 +351,8 @@ export const getUserList = async (req: AuthenticatedRequest, res: Response) => {
|
||||
const totalCount = parseInt(countResult[0]?.total || "0", 10);
|
||||
|
||||
// 사용자 목록 조회
|
||||
const offset = (Number(page) - 1) * Number(countPerPage);
|
||||
const limit = size ? Number(size) : Number(countPerPage);
|
||||
const offset = (Number(page) - 1) * limit;
|
||||
const usersQuery = `
|
||||
SELECT
|
||||
sabun,
|
||||
@@ -357,11 +378,7 @@ export const getUserList = async (req: AuthenticatedRequest, res: Response) => {
|
||||
LIMIT $${paramIndex} OFFSET $${paramIndex + 1}
|
||||
`;
|
||||
|
||||
const users = await query<any>(usersQuery, [
|
||||
...queryParams,
|
||||
Number(countPerPage),
|
||||
offset,
|
||||
]);
|
||||
const users = await query<any>(usersQuery, [...queryParams, limit, offset]);
|
||||
|
||||
// 응답 데이터 가공
|
||||
const processedUsers = users.map((user) => ({
|
||||
@@ -393,8 +410,8 @@ export const getUserList = async (req: AuthenticatedRequest, res: Response) => {
|
||||
searchType,
|
||||
pagination: {
|
||||
page: Number(page),
|
||||
limit: Number(countPerPage),
|
||||
totalPages: Math.ceil(totalCount / Number(countPerPage)),
|
||||
limit: limit,
|
||||
totalPages: Math.ceil(totalCount / limit),
|
||||
},
|
||||
message: "사용자 목록 조회 성공",
|
||||
};
|
||||
@@ -404,7 +421,8 @@ export const getUserList = async (req: AuthenticatedRequest, res: Response) => {
|
||||
returnedCount: processedUsers.length,
|
||||
searchType,
|
||||
currentPage: Number(page),
|
||||
countPerPage: Number(countPerPage),
|
||||
limit: limit,
|
||||
companyCode: companyCode || "all",
|
||||
});
|
||||
|
||||
res.status(200).json(response);
|
||||
@@ -1379,7 +1397,7 @@ export const getDepartmentList = async (
|
||||
|
||||
// 회사 코드 필터
|
||||
if (companyCode) {
|
||||
whereConditions.push(`company_name = $${paramIndex}`);
|
||||
whereConditions.push(`company_code = $${paramIndex}`);
|
||||
queryParams.push(companyCode);
|
||||
paramIndex++;
|
||||
}
|
||||
@@ -1420,6 +1438,7 @@ export const getDepartmentList = async (
|
||||
data_type,
|
||||
status,
|
||||
sales_yn,
|
||||
company_code,
|
||||
company_name
|
||||
FROM dept_info
|
||||
${whereClause}
|
||||
@@ -1445,6 +1464,7 @@ export const getDepartmentList = async (
|
||||
dataType: dept.data_type,
|
||||
status: dept.status || "active",
|
||||
salesYn: dept.sales_yn,
|
||||
companyCode: dept.company_code,
|
||||
companyName: dept.company_name,
|
||||
children: [],
|
||||
});
|
||||
@@ -1480,6 +1500,7 @@ export const getDepartmentList = async (
|
||||
dataType: dept.data_type,
|
||||
status: dept.status || "active",
|
||||
salesYn: dept.sales_yn,
|
||||
companyCode: dept.company_code,
|
||||
companyName: dept.company_name,
|
||||
})),
|
||||
},
|
||||
@@ -1947,10 +1968,23 @@ export const changeUserStatus = async (
|
||||
export const saveUser = async (req: AuthenticatedRequest, res: Response) => {
|
||||
try {
|
||||
const userData = req.body;
|
||||
logger.info("사용자 저장 요청", { userData, user: req.user });
|
||||
const isUpdate = req.method === "PUT"; // PUT 요청이면 수정
|
||||
|
||||
logger.info("사용자 저장 요청", {
|
||||
userData,
|
||||
user: req.user,
|
||||
isUpdate,
|
||||
method: req.method,
|
||||
});
|
||||
|
||||
// 필수 필드 검증
|
||||
const requiredFields = ["userId", "userName", "userPassword"];
|
||||
let requiredFields = ["userId", "userName"];
|
||||
|
||||
// 신규 등록 시에만 비밀번호 필수
|
||||
if (!isUpdate) {
|
||||
requiredFields.push("userPassword");
|
||||
}
|
||||
|
||||
for (const field of requiredFields) {
|
||||
if (!userData[field] || userData[field].trim() === "") {
|
||||
res.status(400).json({
|
||||
@@ -1965,10 +1999,15 @@ export const saveUser = async (req: AuthenticatedRequest, res: Response) => {
|
||||
}
|
||||
}
|
||||
|
||||
// 비밀번호 암호화
|
||||
const encryptedPassword = await EncryptUtil.encrypt(userData.userPassword);
|
||||
// 비밀번호 암호화 (비밀번호가 제공된 경우에만)
|
||||
let encryptedPassword = null;
|
||||
if (userData.userPassword) {
|
||||
encryptedPassword = await EncryptUtil.encrypt(userData.userPassword);
|
||||
}
|
||||
|
||||
// Raw Query를 사용한 사용자 저장 (upsert with ON CONFLICT)
|
||||
const updatePasswordClause = encryptedPassword ? "user_password = $4," : "";
|
||||
|
||||
const [savedUser] = await query<any>(
|
||||
`INSERT INTO user_info (
|
||||
user_id, user_name, user_name_eng, user_password,
|
||||
@@ -1979,7 +2018,7 @@ export const saveUser = async (req: AuthenticatedRequest, res: Response) => {
|
||||
ON CONFLICT (user_id) DO UPDATE SET
|
||||
user_name = $2,
|
||||
user_name_eng = $3,
|
||||
user_password = $4,
|
||||
${updatePasswordClause}
|
||||
dept_code = $5,
|
||||
dept_name = $6,
|
||||
position_code = $7,
|
||||
@@ -1998,7 +2037,7 @@ export const saveUser = async (req: AuthenticatedRequest, res: Response) => {
|
||||
userData.userId,
|
||||
userData.userName,
|
||||
userData.userNameEng || null,
|
||||
encryptedPassword,
|
||||
encryptedPassword || "", // 빈 문자열로 넣되, UPDATE에서는 조건부로 제외
|
||||
userData.deptCode || null,
|
||||
userData.deptName || null,
|
||||
userData.positionCode || null,
|
||||
@@ -2017,23 +2056,26 @@ export const saveUser = async (req: AuthenticatedRequest, res: Response) => {
|
||||
);
|
||||
|
||||
// 기존 사용자인지 새 사용자인지 확인 (regdate로 판단)
|
||||
const isUpdate =
|
||||
const isExistingUser =
|
||||
savedUser.regdate &&
|
||||
new Date(savedUser.regdate).getTime() < Date.now() - 1000;
|
||||
|
||||
logger.info(isUpdate ? "사용자 정보 수정 완료" : "새 사용자 등록 완료", {
|
||||
userId: userData.userId,
|
||||
});
|
||||
logger.info(
|
||||
isExistingUser ? "사용자 정보 수정 완료" : "새 사용자 등록 완료",
|
||||
{
|
||||
userId: userData.userId,
|
||||
}
|
||||
);
|
||||
|
||||
const response = {
|
||||
success: true,
|
||||
result: true,
|
||||
message: isUpdate
|
||||
message: isExistingUser
|
||||
? "사용자 정보가 수정되었습니다."
|
||||
: "사용자가 등록되었습니다.",
|
||||
data: {
|
||||
userId: userData.userId,
|
||||
isUpdate,
|
||||
isUpdate: isExistingUser,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user