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 => { 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 = { 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 => { 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 = { 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 => { 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 = { 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 => { 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 = { 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 => { 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 = { 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 => { 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 = { 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 => { 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 = { 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 => { 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 = { 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 => { 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 = { 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 => { 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 = { 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 => { 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 = { 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 => { 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 = { 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 => { 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 = { 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", }); } };