339 lines
9.2 KiB
TypeScript
339 lines
9.2 KiB
TypeScript
// 배치관리 컨트롤러
|
|
// 작성일: 2024-12-24
|
|
|
|
import { Request, Response } from "express";
|
|
import { BatchService } from "../services/batchService";
|
|
import { BatchSchedulerService } from "../services/batchSchedulerService";
|
|
import {
|
|
BatchConfigFilter,
|
|
CreateBatchConfigRequest,
|
|
UpdateBatchConfigRequest,
|
|
} from "../types/batchTypes";
|
|
|
|
export interface AuthenticatedRequest extends Request {
|
|
user?: {
|
|
userId: string;
|
|
username: string;
|
|
companyCode: string;
|
|
};
|
|
}
|
|
|
|
export class BatchController {
|
|
/**
|
|
* 배치 설정 목록 조회 (회사별)
|
|
* GET /api/batch-configs
|
|
*/
|
|
static async getBatchConfigs(req: AuthenticatedRequest, res: Response) {
|
|
try {
|
|
const { page = 1, limit = 10, search, isActive } = req.query;
|
|
const userCompanyCode = req.user?.companyCode;
|
|
|
|
const filter: BatchConfigFilter = {
|
|
page: Number(page),
|
|
limit: Number(limit),
|
|
search: search as string,
|
|
is_active: isActive as string,
|
|
};
|
|
|
|
const result = await BatchService.getBatchConfigs(
|
|
filter,
|
|
userCompanyCode
|
|
);
|
|
|
|
res.json({
|
|
success: true,
|
|
data: result.data,
|
|
pagination: result.pagination,
|
|
});
|
|
} catch (error) {
|
|
console.error("배치 설정 목록 조회 오류:", error);
|
|
res.status(500).json({
|
|
success: false,
|
|
message: "배치 설정 목록 조회에 실패했습니다.",
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 사용 가능한 커넥션 목록 조회
|
|
* GET /api/batch-configs/connections
|
|
*/
|
|
static async getAvailableConnections(
|
|
req: AuthenticatedRequest,
|
|
res: Response
|
|
) {
|
|
try {
|
|
const result = await BatchService.getAvailableConnections();
|
|
|
|
if (result.success) {
|
|
res.json(result);
|
|
} else {
|
|
res.status(500).json(result);
|
|
}
|
|
} catch (error) {
|
|
console.error("커넥션 목록 조회 오류:", error);
|
|
res.status(500).json({
|
|
success: false,
|
|
message: "커넥션 목록 조회에 실패했습니다.",
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 테이블 목록 조회 (내부/외부 DB)
|
|
* GET /api/batch-configs/connections/:type/tables
|
|
* GET /api/batch-configs/connections/:type/:id/tables
|
|
*/
|
|
static async getTablesFromConnection(
|
|
req: AuthenticatedRequest,
|
|
res: Response
|
|
) {
|
|
try {
|
|
const { type, id } = req.params;
|
|
|
|
if (!type || (type !== "internal" && type !== "external")) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
message: "올바른 연결 타입을 지정해주세요. (internal 또는 external)",
|
|
});
|
|
}
|
|
|
|
const connectionId = type === "external" ? Number(id) : undefined;
|
|
const result = await BatchService.getTablesFromConnection(
|
|
type,
|
|
connectionId
|
|
);
|
|
|
|
if (result.success) {
|
|
return res.json(result);
|
|
} else {
|
|
return res.status(500).json(result);
|
|
}
|
|
} catch (error) {
|
|
console.error("테이블 목록 조회 오류:", error);
|
|
return res.status(500).json({
|
|
success: false,
|
|
message: "테이블 목록 조회에 실패했습니다.",
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 테이블 컬럼 정보 조회 (내부/외부 DB)
|
|
* GET /api/batch-configs/connections/:type/tables/:tableName/columns
|
|
* GET /api/batch-configs/connections/:type/:id/tables/:tableName/columns
|
|
*/
|
|
static async getTableColumns(req: AuthenticatedRequest, res: Response) {
|
|
try {
|
|
const { type, id, tableName } = req.params;
|
|
|
|
if (!type || !tableName) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
message: "연결 타입과 테이블명을 모두 지정해주세요.",
|
|
});
|
|
}
|
|
|
|
if (type !== "internal" && type !== "external") {
|
|
return res.status(400).json({
|
|
success: false,
|
|
message: "올바른 연결 타입을 지정해주세요. (internal 또는 external)",
|
|
});
|
|
}
|
|
|
|
const connectionId = type === "external" ? Number(id) : undefined;
|
|
const result = await BatchService.getTableColumns(
|
|
type,
|
|
connectionId,
|
|
tableName
|
|
);
|
|
|
|
if (result.success) {
|
|
return res.json(result);
|
|
} else {
|
|
return res.status(500).json(result);
|
|
}
|
|
} catch (error) {
|
|
console.error("컬럼 정보 조회 오류:", error);
|
|
return res.status(500).json({
|
|
success: false,
|
|
message: "컬럼 정보 조회에 실패했습니다.",
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 특정 배치 설정 조회 (회사별)
|
|
* GET /api/batch-configs/:id
|
|
*/
|
|
static async getBatchConfigById(req: AuthenticatedRequest, res: Response) {
|
|
try {
|
|
const { id } = req.params;
|
|
const result = await BatchService.getBatchConfigById(Number(id));
|
|
|
|
if (!result.success || !result.data) {
|
|
return res.status(404).json({
|
|
success: false,
|
|
message: result.message || "배치 설정을 찾을 수 없습니다.",
|
|
});
|
|
}
|
|
|
|
return res.json({
|
|
success: true,
|
|
data: result.data,
|
|
});
|
|
} catch (error) {
|
|
console.error("배치 설정 조회 오류:", error);
|
|
return res.status(500).json({
|
|
success: false,
|
|
message: "배치 설정 조회에 실패했습니다.",
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 배치 설정 생성
|
|
* POST /api/batch-configs
|
|
*/
|
|
static async createBatchConfig(req: AuthenticatedRequest, res: Response) {
|
|
try {
|
|
const { batchName, description, cronSchedule, mappings } = req.body;
|
|
|
|
if (
|
|
!batchName ||
|
|
!cronSchedule ||
|
|
!mappings ||
|
|
!Array.isArray(mappings)
|
|
) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
message:
|
|
"필수 필드가 누락되었습니다. (batchName, cronSchedule, mappings)",
|
|
});
|
|
}
|
|
|
|
const batchConfig = await BatchService.createBatchConfig({
|
|
batchName,
|
|
description,
|
|
cronSchedule,
|
|
mappings,
|
|
} as CreateBatchConfigRequest);
|
|
|
|
// 생성된 배치가 활성화 상태라면 스케줄러에 등록 (즉시 실행 비활성화)
|
|
if (
|
|
batchConfig.data &&
|
|
batchConfig.data.is_active === "Y" &&
|
|
batchConfig.data.id
|
|
) {
|
|
await BatchSchedulerService.updateBatchSchedule(
|
|
batchConfig.data.id,
|
|
false
|
|
);
|
|
}
|
|
|
|
return res.status(201).json({
|
|
success: true,
|
|
data: batchConfig,
|
|
message: "배치 설정이 성공적으로 생성되었습니다.",
|
|
});
|
|
} catch (error) {
|
|
console.error("배치 설정 생성 오류:", error);
|
|
return res.status(500).json({
|
|
success: false,
|
|
message: "배치 설정 생성에 실패했습니다.",
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 배치 설정 수정 (회사별)
|
|
* PUT /api/batch-configs/:id
|
|
*/
|
|
static async updateBatchConfig(req: AuthenticatedRequest, res: Response) {
|
|
try {
|
|
const { id } = req.params;
|
|
const { batchName, description, cronSchedule, mappings, isActive } =
|
|
req.body;
|
|
const userId = req.user?.userId;
|
|
const userCompanyCode = req.user?.companyCode;
|
|
|
|
if (!batchName || !cronSchedule) {
|
|
return res.status(400).json({
|
|
success: false,
|
|
message: "필수 필드가 누락되었습니다. (batchName, cronSchedule)",
|
|
});
|
|
}
|
|
|
|
const batchConfig = await BatchService.updateBatchConfig(
|
|
Number(id),
|
|
{
|
|
batchName,
|
|
description,
|
|
cronSchedule,
|
|
mappings,
|
|
isActive,
|
|
} as UpdateBatchConfigRequest,
|
|
userId,
|
|
userCompanyCode
|
|
);
|
|
|
|
if (!batchConfig) {
|
|
return res.status(404).json({
|
|
success: false,
|
|
message: "배치 설정을 찾을 수 없습니다.",
|
|
});
|
|
}
|
|
|
|
// 스케줄러에서 배치 스케줄 업데이트 (즉시 실행 비활성화)
|
|
await BatchSchedulerService.updateBatchSchedule(Number(id), false);
|
|
|
|
return res.json({
|
|
success: true,
|
|
data: batchConfig,
|
|
message: "배치 설정이 성공적으로 수정되었습니다.",
|
|
});
|
|
} catch (error) {
|
|
console.error("배치 설정 수정 오류:", error);
|
|
return res.status(500).json({
|
|
success: false,
|
|
message: "배치 설정 수정에 실패했습니다.",
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 배치 설정 삭제 (논리 삭제, 회사별)
|
|
* DELETE /api/batch-configs/:id
|
|
*/
|
|
static async deleteBatchConfig(req: AuthenticatedRequest, res: Response) {
|
|
try {
|
|
const { id } = req.params;
|
|
const userId = req.user?.userId;
|
|
const userCompanyCode = req.user?.companyCode;
|
|
const result = await BatchService.deleteBatchConfig(
|
|
Number(id),
|
|
userId,
|
|
userCompanyCode
|
|
);
|
|
|
|
if (!result) {
|
|
return res.status(404).json({
|
|
success: false,
|
|
message: "배치 설정을 찾을 수 없습니다.",
|
|
});
|
|
}
|
|
|
|
return res.json({
|
|
success: true,
|
|
message: "배치 설정이 성공적으로 삭제되었습니다.",
|
|
});
|
|
} catch (error) {
|
|
console.error("배치 설정 삭제 오류:", error);
|
|
return res.status(500).json({
|
|
success: false,
|
|
message: "배치 설정 삭제에 실패했습니다.",
|
|
});
|
|
}
|
|
}
|
|
}
|