ERP-node/backend-node/src/controllers/roleController.ts

865 lines
22 KiB
TypeScript

import { Response } from "express";
import { AuthenticatedRequest } from "../types/auth";
import { ApiResponse } from "../types/common";
import { RoleService } from "../services/roleService";
import { logger } from "../utils/logger";
import {
isSuperAdmin,
isCompanyAdmin,
canAccessCompanyData,
} from "../utils/permissionUtils";
/**
* 권한 그룹 목록 조회
* - 회사 관리자: 자기 회사 권한 그룹만 조회
* - 최고 관리자: 모든 회사 권한 그룹 조회 (companyCode 미지정 시 전체 조회)
*/
export const getRoleGroups = async (
req: AuthenticatedRequest,
res: Response
): Promise<void> => {
try {
const search = req.query.search as string | undefined;
const companyCode = req.query.companyCode as string | undefined;
// 최고 관리자가 아닌 경우 자기 회사만 조회
let targetCompanyCode: string | undefined;
if (isSuperAdmin(req.user)) {
// 최고 관리자: companyCode 파라미터가 있으면 해당 회사만, 없으면 전체 조회
targetCompanyCode = companyCode;
logger.info("권한 그룹 목록 조회 (최고 관리자)", {
userId: req.user?.userId,
targetCompanyCode: targetCompanyCode || "전체",
search,
});
} else {
// 일반 관리자: 자기 회사만 조회
targetCompanyCode = req.user?.companyCode;
if (!targetCompanyCode) {
res.status(400).json({
success: false,
message: "회사 코드가 필요합니다",
});
return;
}
logger.info("권한 그룹 목록 조회 (회사 관리자)", {
userId: req.user?.userId,
companyCode: targetCompanyCode,
search,
});
}
const roleGroups = await RoleService.getRoleGroups(
targetCompanyCode,
search
);
const response: ApiResponse<any[]> = {
success: true,
message: "권한 그룹 목록 조회 성공",
data: roleGroups,
};
res.status(200).json(response);
} catch (error) {
logger.error("권한 그룹 목록 조회 실패", { error });
res.status(500).json({
success: false,
message: "권한 그룹 목록 조회 중 오류가 발생했습니다",
error: error instanceof Error ? error.message : "Unknown error",
});
}
};
/**
* 권한 그룹 상세 조회
*/
export const getRoleGroupById = async (
req: AuthenticatedRequest,
res: Response
): Promise<void> => {
try {
const objid = parseInt(req.params.id, 10);
if (isNaN(objid)) {
res.status(400).json({
success: false,
message: "유효하지 않은 권한 그룹 ID입니다",
});
return;
}
const roleGroup = await RoleService.getRoleGroupById(objid);
if (!roleGroup) {
res.status(404).json({
success: false,
message: "권한 그룹을 찾을 수 없습니다",
});
return;
}
// 권한 체크: 슈퍼관리자 또는 해당 회사 관리자만 조회 가능
if (
!isSuperAdmin(req.user) &&
!canAccessCompanyData(req.user, roleGroup.companyCode)
) {
res.status(403).json({
success: false,
message: "권한이 없습니다",
});
return;
}
const response: ApiResponse<any> = {
success: true,
message: "권한 그룹 상세 조회 성공",
data: roleGroup,
};
res.status(200).json(response);
} catch (error) {
logger.error("권한 그룹 상세 조회 실패", { error });
res.status(500).json({
success: false,
message: "권한 그룹 상세 조회 중 오류가 발생했습니다",
error: error instanceof Error ? error.message : "Unknown error",
});
}
};
/**
* 권한 그룹 생성
* - 회사 관리자: 자기 회사에만 권한 그룹 생성 가능
* - 최고 관리자: 모든 회사에 권한 그룹 생성 가능
*/
export const createRoleGroup = async (
req: AuthenticatedRequest,
res: Response
): Promise<void> => {
try {
const { authName, authCode, companyCode } = req.body;
if (!authName || !authCode || !companyCode) {
res.status(400).json({
success: false,
message: "필수 정보가 누락되었습니다 (authName, authCode, companyCode)",
});
return;
}
// 권한 체크: 회사 관리자 이상만 생성 가능
if (!isSuperAdmin(req.user) && !isCompanyAdmin(req.user)) {
res.status(403).json({
success: false,
message: "권한 그룹 생성 권한이 없습니다",
});
return;
}
// 회사 관리자는 자기 회사에만 권한 그룹 생성 가능
if (!isSuperAdmin(req.user) && req.user?.companyCode !== companyCode) {
res.status(403).json({
success: false,
message: "다른 회사의 권한 그룹을 생성할 수 없습니다",
});
return;
}
const roleGroup = await RoleService.createRoleGroup({
authName,
authCode,
companyCode,
writer: req.user?.userId || "SYSTEM",
});
const response: ApiResponse<any> = {
success: true,
message: "권한 그룹 생성 성공",
data: roleGroup,
};
res.status(201).json(response);
} catch (error) {
logger.error("권한 그룹 생성 실패", { error });
res.status(500).json({
success: false,
message: "권한 그룹 생성 중 오류가 발생했습니다",
error: error instanceof Error ? error.message : "Unknown error",
});
}
};
/**
* 권한 그룹 수정
*/
export const updateRoleGroup = async (
req: AuthenticatedRequest,
res: Response
): Promise<void> => {
try {
const objid = parseInt(req.params.id, 10);
const { authName, authCode, status } = req.body;
if (isNaN(objid)) {
res.status(400).json({
success: false,
message: "유효하지 않은 권한 그룹 ID입니다",
});
return;
}
// 기존 권한 그룹 조회
const existingRoleGroup = await RoleService.getRoleGroupById(objid);
if (!existingRoleGroup) {
res.status(404).json({
success: false,
message: "권한 그룹을 찾을 수 없습니다",
});
return;
}
// 권한 체크
if (
!isSuperAdmin(req.user) &&
!canAccessCompanyData(req.user, existingRoleGroup.companyCode)
) {
res.status(403).json({
success: false,
message: "권한 그룹 수정 권한이 없습니다",
});
return;
}
const roleGroup = await RoleService.updateRoleGroup(objid, {
authName,
authCode,
status,
});
const response: ApiResponse<any> = {
success: true,
message: "권한 그룹 수정 성공",
data: roleGroup,
};
res.status(200).json(response);
} catch (error) {
logger.error("권한 그룹 수정 실패", { error });
res.status(500).json({
success: false,
message: "권한 그룹 수정 중 오류가 발생했습니다",
error: error instanceof Error ? error.message : "Unknown error",
});
}
};
/**
* 권한 그룹 삭제
*/
export const deleteRoleGroup = async (
req: AuthenticatedRequest,
res: Response
): Promise<void> => {
try {
const objid = parseInt(req.params.id, 10);
if (isNaN(objid)) {
res.status(400).json({
success: false,
message: "유효하지 않은 권한 그룹 ID입니다",
});
return;
}
// 기존 권한 그룹 조회
const existingRoleGroup = await RoleService.getRoleGroupById(objid);
if (!existingRoleGroup) {
res.status(404).json({
success: false,
message: "권한 그룹을 찾을 수 없습니다",
});
return;
}
// 권한 체크
if (
!isSuperAdmin(req.user) &&
!canAccessCompanyData(req.user, existingRoleGroup.companyCode)
) {
res.status(403).json({
success: false,
message: "권한 그룹 삭제 권한이 없습니다",
});
return;
}
await RoleService.deleteRoleGroup(objid);
const response: ApiResponse<null> = {
success: true,
message: "권한 그룹 삭제 성공",
data: null,
};
res.status(200).json(response);
} catch (error) {
logger.error("권한 그룹 삭제 실패", { error });
res.status(500).json({
success: false,
message: "권한 그룹 삭제 중 오류가 발생했습니다",
error: error instanceof Error ? error.message : "Unknown error",
});
}
};
/**
* 권한 그룹 멤버 목록 조회
*/
export const getRoleMembers = async (
req: AuthenticatedRequest,
res: Response
): Promise<void> => {
try {
const masterObjid = parseInt(req.params.id, 10);
if (isNaN(masterObjid)) {
res.status(400).json({
success: false,
message: "유효하지 않은 권한 그룹 ID입니다",
});
return;
}
// 기존 권한 그룹 조회
const roleGroup = await RoleService.getRoleGroupById(masterObjid);
if (!roleGroup) {
res.status(404).json({
success: false,
message: "권한 그룹을 찾을 수 없습니다",
});
return;
}
// 권한 체크
if (
!isSuperAdmin(req.user) &&
!canAccessCompanyData(req.user, roleGroup.companyCode)
) {
res.status(403).json({
success: false,
message: "권한 그룹 멤버 조회 권한이 없습니다",
});
return;
}
const members = await RoleService.getRoleMembers(masterObjid);
const response: ApiResponse<any[]> = {
success: true,
message: "권한 그룹 멤버 조회 성공",
data: members,
};
res.status(200).json(response);
} catch (error) {
logger.error("권한 그룹 멤버 조회 실패", { error });
res.status(500).json({
success: false,
message: "권한 그룹 멤버 조회 중 오류가 발생했습니다",
error: error instanceof Error ? error.message : "Unknown error",
});
}
};
/**
* 권한 그룹 멤버 추가
*/
export const addRoleMembers = async (
req: AuthenticatedRequest,
res: Response
): Promise<void> => {
try {
const masterObjid = parseInt(req.params.id, 10);
const { userIds } = req.body;
if (isNaN(masterObjid)) {
res.status(400).json({
success: false,
message: "유효하지 않은 권한 그룹 ID입니다",
});
return;
}
if (!Array.isArray(userIds) || userIds.length === 0) {
res.status(400).json({
success: false,
message: "추가할 사용자 ID 목록이 필요합니다",
});
return;
}
// 기존 권한 그룹 조회
const roleGroup = await RoleService.getRoleGroupById(masterObjid);
if (!roleGroup) {
res.status(404).json({
success: false,
message: "권한 그룹을 찾을 수 없습니다",
});
return;
}
// 권한 체크
if (
!isSuperAdmin(req.user) &&
!canAccessCompanyData(req.user, roleGroup.companyCode)
) {
res.status(403).json({
success: false,
message: "권한 그룹 멤버 추가 권한이 없습니다",
});
return;
}
await RoleService.addRoleMembers(
masterObjid,
userIds,
req.user?.userId || "SYSTEM"
);
const response: ApiResponse<null> = {
success: true,
message: "권한 그룹 멤버 추가 성공",
data: null,
};
res.status(200).json(response);
} catch (error) {
logger.error("권한 그룹 멤버 추가 실패", { error });
res.status(500).json({
success: false,
message: "권한 그룹 멤버 추가 중 오류가 발생했습니다",
error: error instanceof Error ? error.message : "Unknown error",
});
}
};
/**
* 권한 그룹 멤버 일괄 업데이트
*/
export const updateRoleMembers = async (
req: AuthenticatedRequest,
res: Response
): Promise<void> => {
try {
const masterObjid = parseInt(req.params.id, 10);
const { userIds } = req.body;
if (isNaN(masterObjid)) {
res.status(400).json({
success: false,
message: "유효하지 않은 권한 그룹 ID입니다",
});
return;
}
if (!Array.isArray(userIds)) {
res.status(400).json({
success: false,
message: "사용자 ID 배열이 필요합니다",
});
return;
}
// 기존 권한 그룹 조회
const roleGroup = await RoleService.getRoleGroupById(masterObjid);
if (!roleGroup) {
res.status(404).json({
success: false,
message: "권한 그룹을 찾을 수 없습니다",
});
return;
}
// 권한 체크
if (
!isSuperAdmin(req.user) &&
!canAccessCompanyData(req.user, roleGroup.companyCode)
) {
res.status(403).json({
success: false,
message: "권한 그룹 멤버 수정 권한이 없습니다",
});
return;
}
// 기존 멤버 조회
const existingMembers = await RoleService.getRoleMembers(masterObjid);
const existingUserIds = existingMembers.map((m: any) => m.userId);
// 추가할 멤버 (새로 추가된 것들)
const toAdd = userIds.filter((id: string) => !existingUserIds.includes(id));
// 제거할 멤버 (기존에 있었는데 없어진 것들)
const toRemove = existingUserIds.filter(
(id: string) => !userIds.includes(id)
);
// 추가
if (toAdd.length > 0) {
await RoleService.addRoleMembers(
masterObjid,
toAdd,
req.user?.userId || "SYSTEM"
);
}
// 제거
if (toRemove.length > 0) {
await RoleService.removeRoleMembers(
masterObjid,
toRemove,
req.user?.userId || "SYSTEM"
);
}
logger.info("권한 그룹 멤버 일괄 업데이트 성공", {
masterObjid,
added: toAdd.length,
removed: toRemove.length,
});
const response: ApiResponse<null> = {
success: true,
message: "권한 그룹 멤버가 업데이트되었습니다",
data: null,
};
res.status(200).json(response);
} catch (error) {
logger.error("권한 그룹 멤버 업데이트 실패", { error });
res.status(500).json({
success: false,
message: "권한 그룹 멤버 업데이트 중 오류가 발생했습니다",
error: error instanceof Error ? error.message : "Unknown error",
});
}
};
/**
* 권한 그룹 멤버 제거
*/
export const removeRoleMembers = async (
req: AuthenticatedRequest,
res: Response
): Promise<void> => {
try {
const masterObjid = parseInt(req.params.id, 10);
const { userIds } = req.body;
if (isNaN(masterObjid)) {
res.status(400).json({
success: false,
message: "유효하지 않은 권한 그룹 ID입니다",
});
return;
}
if (!Array.isArray(userIds) || userIds.length === 0) {
res.status(400).json({
success: false,
message: "제거할 사용자 ID 목록이 필요합니다",
});
return;
}
// 기존 권한 그룹 조회
const roleGroup = await RoleService.getRoleGroupById(masterObjid);
if (!roleGroup) {
res.status(404).json({
success: false,
message: "권한 그룹을 찾을 수 없습니다",
});
return;
}
// 권한 체크
if (
!isSuperAdmin(req.user) &&
!canAccessCompanyData(req.user, roleGroup.companyCode)
) {
res.status(403).json({
success: false,
message: "권한 그룹 멤버 제거 권한이 없습니다",
});
return;
}
await RoleService.removeRoleMembers(
masterObjid,
userIds,
req.user?.userId || "SYSTEM"
);
const response: ApiResponse<null> = {
success: true,
message: "권한 그룹 멤버 제거 성공",
data: null,
};
res.status(200).json(response);
} catch (error) {
logger.error("권한 그룹 멤버 제거 실패", { error });
res.status(500).json({
success: false,
message: "권한 그룹 멤버 제거 중 오류가 발생했습니다",
error: error instanceof Error ? error.message : "Unknown error",
});
}
};
/**
* 메뉴 권한 목록 조회
*/
export const getMenuPermissions = async (
req: AuthenticatedRequest,
res: Response
): Promise<void> => {
try {
const authObjid = parseInt(req.params.id, 10);
if (isNaN(authObjid)) {
res.status(400).json({
success: false,
message: "유효하지 않은 권한 그룹 ID입니다",
});
return;
}
// 기존 권한 그룹 조회
const roleGroup = await RoleService.getRoleGroupById(authObjid);
if (!roleGroup) {
res.status(404).json({
success: false,
message: "권한 그룹을 찾을 수 없습니다",
});
return;
}
// 권한 체크
if (
!isSuperAdmin(req.user) &&
!canAccessCompanyData(req.user, roleGroup.companyCode)
) {
res.status(403).json({
success: false,
message: "메뉴 권한 조회 권한이 없습니다",
});
return;
}
const permissions = await RoleService.getMenuPermissions(authObjid);
const response: ApiResponse<any[]> = {
success: true,
message: "메뉴 권한 조회 성공",
data: permissions,
};
res.status(200).json(response);
} catch (error) {
logger.error("메뉴 권한 조회 실패", { error });
res.status(500).json({
success: false,
message: "메뉴 권한 조회 중 오류가 발생했습니다",
error: error instanceof Error ? error.message : "Unknown error",
});
}
};
/**
* 메뉴 권한 설정
*/
export const setMenuPermissions = async (
req: AuthenticatedRequest,
res: Response
): Promise<void> => {
try {
const authObjid = parseInt(req.params.id, 10);
const { permissions } = req.body;
if (isNaN(authObjid)) {
res.status(400).json({
success: false,
message: "유효하지 않은 권한 그룹 ID입니다",
});
return;
}
if (!Array.isArray(permissions)) {
res.status(400).json({
success: false,
message: "권한 목록이 필요합니다",
});
return;
}
// 기존 권한 그룹 조회
const roleGroup = await RoleService.getRoleGroupById(authObjid);
if (!roleGroup) {
res.status(404).json({
success: false,
message: "권한 그룹을 찾을 수 없습니다",
});
return;
}
// 권한 체크
if (
!isSuperAdmin(req.user) &&
!canAccessCompanyData(req.user, roleGroup.companyCode)
) {
res.status(403).json({
success: false,
message: "메뉴 권한 설정 권한이 없습니다",
});
return;
}
await RoleService.setMenuPermissions(
authObjid,
permissions,
req.user?.userId || "SYSTEM"
);
const response: ApiResponse<null> = {
success: true,
message: "메뉴 권한 설정 성공",
data: null,
};
res.status(200).json(response);
} catch (error) {
logger.error("메뉴 권한 설정 실패", { error });
res.status(500).json({
success: false,
message: "메뉴 권한 설정 중 오류가 발생했습니다",
error: error instanceof Error ? error.message : "Unknown error",
});
}
};
/**
* 사용자가 속한 권한 그룹 목록 조회
*/
export const getUserRoleGroups = async (
req: AuthenticatedRequest,
res: Response
): Promise<void> => {
try {
const userId = req.params.userId || req.user?.userId;
const companyCode = req.user?.companyCode;
if (!userId || !companyCode) {
res.status(400).json({
success: false,
message: "사용자 ID 또는 회사 코드가 필요합니다",
});
return;
}
const roleGroups = await RoleService.getUserRoleGroups(userId, companyCode);
const response: ApiResponse<any[]> = {
success: true,
message: "사용자 권한 그룹 조회 성공",
data: roleGroups,
};
res.status(200).json(response);
} catch (error) {
logger.error("사용자 권한 그룹 조회 실패", { error });
res.status(500).json({
success: false,
message: "사용자 권한 그룹 조회 중 오류가 발생했습니다",
error: error instanceof Error ? error.message : "Unknown error",
});
}
};
/**
* 전체 메뉴 목록 조회 (권한 설정용)
*/
export const getAllMenus = async (
req: AuthenticatedRequest,
res: Response
): Promise<void> => {
try {
const requestedCompanyCode = req.query.companyCode as string | undefined;
logger.info("🔍 [getAllMenus] API 호출", {
userId: req.user?.userId,
userType: req.user?.userType,
userCompanyCode: req.user?.companyCode,
requestedCompanyCode,
});
// 권한 체크
if (!isSuperAdmin(req.user) && !isCompanyAdmin(req.user)) {
logger.warn("❌ [getAllMenus] 권한 없음", {
userId: req.user?.userId,
userType: req.user?.userType,
});
res.status(403).json({
success: false,
message: "관리자 권한이 필요합니다",
});
return;
}
// 회사 코드 결정: 최고 관리자는 요청한 코드 사용, 회사 관리자는 자기 회사만
let companyCode: string | undefined;
if (isSuperAdmin(req.user)) {
// 최고 관리자: 요청한 회사 코드 사용 (없으면 전체)
companyCode = requestedCompanyCode;
logger.info("✅ [getAllMenus] 최고 관리자 - 요청된 회사 코드 사용", {
companyCode: companyCode || "전체",
});
} else {
// 회사 관리자: 자기 회사 코드만 사용
companyCode = req.user?.companyCode;
logger.info("✅ [getAllMenus] 회사 관리자 - 자기 회사 코드 적용", {
companyCode,
});
}
logger.info("✅ [getAllMenus] 관리자 권한 확인 완료", {
isSuperAdmin: isSuperAdmin(req.user),
isCompanyAdmin: isCompanyAdmin(req.user),
finalCompanyCode: companyCode || "전체",
});
const menus = await RoleService.getAllMenus(companyCode);
logger.info("✅ [getAllMenus] API 응답 준비", {
menuCount: menus.length,
companyCode: companyCode || "전체",
});
const response: ApiResponse<any[]> = {
success: true,
message: "메뉴 목록 조회 성공",
data: menus,
};
res.status(200).json(response);
} catch (error) {
logger.error("❌ [getAllMenus] 메뉴 목록 조회 실패", { error });
res.status(500).json({
success: false,
message: "메뉴 목록 조회 중 오류가 발생했습니다",
error: error instanceof Error ? error.message : "Unknown error",
});
}
};