feat: 인증 미들웨어 적용 및 화면 그룹 삭제 로직 개선
- 모든 라우트에 인증 미들웨어를 적용하여 보안을 강화하였습니다. - 화면 그룹 삭제 시 회사 코드 확인 및 권한 체크 로직을 추가하여, 다른 회사의 그룹 삭제를 방지하였습니다. - 채번 규칙, 카테고리 값, 테이블 타입 컬럼 복제 시 같은 회사로 복제하는 경우 경고 메시지를 추가하였습니다. - 메뉴 URL 업데이트 기능을 추가하여 복제된 화면 ID에 맞게 URL을 재매핑하도록 하였습니다.
This commit is contained in:
@@ -961,6 +961,16 @@ export class MenuCopyService {
|
||||
const menus = await this.collectMenuTree(sourceMenuObjid, client);
|
||||
const sourceCompanyCode = menus[0].company_code!;
|
||||
|
||||
// 같은 회사로 복제하는 경우 경고 (자기 자신의 데이터 손상 위험)
|
||||
if (sourceCompanyCode === targetCompanyCode) {
|
||||
logger.warn(
|
||||
`⚠️ 같은 회사로 메뉴 복제 시도: ${sourceCompanyCode} → ${targetCompanyCode}`
|
||||
);
|
||||
warnings.push(
|
||||
"같은 회사로 복제하면 추가 데이터(카테고리, 채번 등)가 복제되지 않습니다."
|
||||
);
|
||||
}
|
||||
|
||||
const screenIds = await this.collectScreens(
|
||||
menus.map((m) => m.objid),
|
||||
sourceCompanyCode,
|
||||
@@ -1116,6 +1126,10 @@ export class MenuCopyService {
|
||||
client
|
||||
);
|
||||
|
||||
// === 6.5단계: 메뉴 URL 업데이트 (화면 ID 재매핑) ===
|
||||
logger.info("\n🔄 [6.5단계] 메뉴 URL 화면 ID 재매핑");
|
||||
await this.updateMenuUrls(menuIdMap, screenIdMap, client);
|
||||
|
||||
// === 7단계: 테이블 타입 설정 복사 ===
|
||||
if (additionalCopyOptions?.copyTableTypeColumns) {
|
||||
logger.info("\n📦 [7단계] 테이블 타입 설정 복사");
|
||||
@@ -2268,6 +2282,68 @@ export class MenuCopyService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 메뉴 URL 업데이트 (화면 ID 재매핑)
|
||||
* menu_url에 포함된 /screens/{screenId} 형식의 화면 ID를 복제된 화면 ID로 교체
|
||||
*/
|
||||
private async updateMenuUrls(
|
||||
menuIdMap: Map<number, number>,
|
||||
screenIdMap: Map<number, number>,
|
||||
client: PoolClient
|
||||
): Promise<void> {
|
||||
if (menuIdMap.size === 0 || screenIdMap.size === 0) {
|
||||
logger.info("📭 메뉴 URL 업데이트 대상 없음");
|
||||
return;
|
||||
}
|
||||
|
||||
const newMenuObjids = Array.from(menuIdMap.values());
|
||||
|
||||
// 복제된 메뉴 중 menu_url이 있는 것 조회
|
||||
const menusWithUrl = await client.query<{
|
||||
objid: number;
|
||||
menu_url: string;
|
||||
}>(
|
||||
`SELECT objid, menu_url FROM menu_info
|
||||
WHERE objid = ANY($1) AND menu_url IS NOT NULL AND menu_url != ''`,
|
||||
[newMenuObjids]
|
||||
);
|
||||
|
||||
if (menusWithUrl.rows.length === 0) {
|
||||
logger.info("📭 menu_url 업데이트 대상 없음");
|
||||
return;
|
||||
}
|
||||
|
||||
let updatedCount = 0;
|
||||
const screenIdPattern = /\/screens\/(\d+)/;
|
||||
|
||||
for (const menu of menusWithUrl.rows) {
|
||||
const match = menu.menu_url.match(screenIdPattern);
|
||||
if (!match) continue;
|
||||
|
||||
const originalScreenId = parseInt(match[1], 10);
|
||||
const newScreenId = screenIdMap.get(originalScreenId);
|
||||
|
||||
if (newScreenId && newScreenId !== originalScreenId) {
|
||||
const newMenuUrl = menu.menu_url.replace(
|
||||
`/screens/${originalScreenId}`,
|
||||
`/screens/${newScreenId}`
|
||||
);
|
||||
|
||||
await client.query(
|
||||
`UPDATE menu_info SET menu_url = $1 WHERE objid = $2`,
|
||||
[newMenuUrl, menu.objid]
|
||||
);
|
||||
|
||||
logger.info(
|
||||
` 🔗 메뉴 URL 업데이트: ${menu.menu_url} → ${newMenuUrl}`
|
||||
);
|
||||
updatedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
logger.info(`✅ 메뉴 URL 업데이트 완료: ${updatedCount}개`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 코드 카테고리 + 코드 복사 (최적화: 배치 조회/삽입)
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user