313 lines
9.1 KiB
TypeScript
313 lines
9.1 KiB
TypeScript
|
|
// 배치관리 컨트롤러
|
||
|
|
// 작성일: 2024-12-24
|
||
|
|
|
||
|
|
import { Request, Response } from "express";
|
||
|
|
import { BatchService } from "../services/batchService";
|
||
|
|
import { BatchConfigFilter, BatchMappingRequest } 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 filter: BatchConfigFilter = {
|
||
|
|
is_active: req.query.is_active as string,
|
||
|
|
company_code: req.query.company_code as string,
|
||
|
|
search: req.query.search as string,
|
||
|
|
};
|
||
|
|
|
||
|
|
// 빈 값 제거
|
||
|
|
Object.keys(filter).forEach((key) => {
|
||
|
|
if (!filter[key as keyof BatchConfigFilter]) {
|
||
|
|
delete filter[key as keyof BatchConfigFilter];
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
const result = await BatchService.getBatchConfigs(filter);
|
||
|
|
|
||
|
|
if (result.success) {
|
||
|
|
return res.status(200).json(result);
|
||
|
|
} else {
|
||
|
|
return res.status(400).json(result);
|
||
|
|
}
|
||
|
|
} catch (error) {
|
||
|
|
console.error("배치 설정 목록 조회 오류:", error);
|
||
|
|
return res.status(500).json({
|
||
|
|
success: false,
|
||
|
|
message: "서버 내부 오류가 발생했습니다.",
|
||
|
|
error: error instanceof Error ? error.message : "알 수 없는 오류",
|
||
|
|
});
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 특정 배치 설정 조회
|
||
|
|
* GET /api/batch-configs/:id
|
||
|
|
*/
|
||
|
|
static async getBatchConfigById(req: AuthenticatedRequest, res: Response) {
|
||
|
|
try {
|
||
|
|
const id = parseInt(req.params.id);
|
||
|
|
|
||
|
|
if (isNaN(id)) {
|
||
|
|
return res.status(400).json({
|
||
|
|
success: false,
|
||
|
|
message: "유효하지 않은 배치 설정 ID입니다.",
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
const result = await BatchService.getBatchConfigById(id);
|
||
|
|
|
||
|
|
if (result.success) {
|
||
|
|
return res.status(200).json(result);
|
||
|
|
} else {
|
||
|
|
return res.status(404).json(result);
|
||
|
|
}
|
||
|
|
} catch (error) {
|
||
|
|
console.error("배치 설정 조회 오류:", error);
|
||
|
|
return res.status(500).json({
|
||
|
|
success: false,
|
||
|
|
message: "서버 내부 오류가 발생했습니다.",
|
||
|
|
error: error instanceof Error ? error.message : "알 수 없는 오류",
|
||
|
|
});
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 배치 설정 생성
|
||
|
|
* POST /api/batch-configs
|
||
|
|
*/
|
||
|
|
static async createBatchConfig(req: AuthenticatedRequest, res: Response) {
|
||
|
|
try {
|
||
|
|
const data: BatchMappingRequest = req.body;
|
||
|
|
|
||
|
|
// 필수 필드 검증
|
||
|
|
if (!data.batch_name || !data.cron_schedule || !data.mappings) {
|
||
|
|
return res.status(400).json({
|
||
|
|
success: false,
|
||
|
|
message: "필수 필드가 누락되었습니다. (batch_name, cron_schedule, mappings)",
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
const result = await BatchService.createBatchConfig(
|
||
|
|
data,
|
||
|
|
req.user?.userId
|
||
|
|
);
|
||
|
|
|
||
|
|
if (result.success) {
|
||
|
|
return res.status(201).json(result);
|
||
|
|
} else {
|
||
|
|
return res.status(400).json(result);
|
||
|
|
}
|
||
|
|
} catch (error) {
|
||
|
|
console.error("배치 설정 생성 오류:", error);
|
||
|
|
return res.status(500).json({
|
||
|
|
success: false,
|
||
|
|
message: "서버 내부 오류가 발생했습니다.",
|
||
|
|
error: error instanceof Error ? error.message : "알 수 없는 오류",
|
||
|
|
});
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 배치 설정 수정
|
||
|
|
* PUT /api/batch-configs/:id
|
||
|
|
*/
|
||
|
|
static async updateBatchConfig(req: AuthenticatedRequest, res: Response) {
|
||
|
|
try {
|
||
|
|
const id = parseInt(req.params.id);
|
||
|
|
const data: Partial<BatchMappingRequest> = req.body;
|
||
|
|
|
||
|
|
if (isNaN(id)) {
|
||
|
|
return res.status(400).json({
|
||
|
|
success: false,
|
||
|
|
message: "유효하지 않은 배치 설정 ID입니다.",
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
const result = await BatchService.updateBatchConfig(
|
||
|
|
id,
|
||
|
|
data,
|
||
|
|
req.user?.userId
|
||
|
|
);
|
||
|
|
|
||
|
|
if (result.success) {
|
||
|
|
return res.status(200).json(result);
|
||
|
|
} else {
|
||
|
|
return res.status(400).json(result);
|
||
|
|
}
|
||
|
|
} catch (error) {
|
||
|
|
console.error("배치 설정 수정 오류:", error);
|
||
|
|
return res.status(500).json({
|
||
|
|
success: false,
|
||
|
|
message: "서버 내부 오류가 발생했습니다.",
|
||
|
|
error: error instanceof Error ? error.message : "알 수 없는 오류",
|
||
|
|
});
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 배치 설정 삭제
|
||
|
|
* DELETE /api/batch-configs/:id
|
||
|
|
*/
|
||
|
|
static async deleteBatchConfig(req: AuthenticatedRequest, res: Response) {
|
||
|
|
try {
|
||
|
|
const id = parseInt(req.params.id);
|
||
|
|
|
||
|
|
if (isNaN(id)) {
|
||
|
|
return res.status(400).json({
|
||
|
|
success: false,
|
||
|
|
message: "유효하지 않은 배치 설정 ID입니다.",
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
const result = await BatchService.deleteBatchConfig(
|
||
|
|
id,
|
||
|
|
req.user?.userId
|
||
|
|
);
|
||
|
|
|
||
|
|
if (result.success) {
|
||
|
|
return res.status(200).json(result);
|
||
|
|
} else {
|
||
|
|
return res.status(404).json(result);
|
||
|
|
}
|
||
|
|
} catch (error) {
|
||
|
|
console.error("배치 설정 삭제 오류:", error);
|
||
|
|
return res.status(500).json({
|
||
|
|
success: false,
|
||
|
|
message: "서버 내부 오류가 발생했습니다.",
|
||
|
|
error: error instanceof Error ? error.message : "알 수 없는 오류",
|
||
|
|
});
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 사용 가능한 커넥션 목록 조회
|
||
|
|
* GET /api/batch-configs/connections
|
||
|
|
*/
|
||
|
|
static async getAvailableConnections(req: AuthenticatedRequest, res: Response) {
|
||
|
|
try {
|
||
|
|
const result = await BatchService.getAvailableConnections();
|
||
|
|
|
||
|
|
if (result.success) {
|
||
|
|
return res.status(200).json(result);
|
||
|
|
} else {
|
||
|
|
return res.status(400).json(result);
|
||
|
|
}
|
||
|
|
} catch (error) {
|
||
|
|
console.error("커넥션 목록 조회 오류:", error);
|
||
|
|
return res.status(500).json({
|
||
|
|
success: false,
|
||
|
|
message: "서버 내부 오류가 발생했습니다.",
|
||
|
|
error: error instanceof Error ? error.message : "알 수 없는 오류",
|
||
|
|
});
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 특정 커넥션의 테이블 목록 조회
|
||
|
|
* GET /api/batch-configs/connections/:type/tables
|
||
|
|
* GET /api/batch-configs/connections/:type/:id/tables
|
||
|
|
*/
|
||
|
|
static async getTablesFromConnection(req: AuthenticatedRequest, res: Response) {
|
||
|
|
try {
|
||
|
|
const connectionType = req.params.type as 'internal' | 'external';
|
||
|
|
const connectionId = req.params.id ? parseInt(req.params.id) : undefined;
|
||
|
|
|
||
|
|
if (connectionType !== 'internal' && connectionType !== 'external') {
|
||
|
|
return res.status(400).json({
|
||
|
|
success: false,
|
||
|
|
message: "유효하지 않은 커넥션 타입입니다. (internal 또는 external)",
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
if (connectionType === 'external' && (!connectionId || isNaN(connectionId))) {
|
||
|
|
return res.status(400).json({
|
||
|
|
success: false,
|
||
|
|
message: "외부 커넥션의 경우 유효한 커넥션 ID가 필요합니다.",
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
const result = await BatchService.getTablesFromConnection(
|
||
|
|
connectionType,
|
||
|
|
connectionId
|
||
|
|
);
|
||
|
|
|
||
|
|
if (result.success) {
|
||
|
|
return res.status(200).json(result);
|
||
|
|
} else {
|
||
|
|
return res.status(400).json(result);
|
||
|
|
}
|
||
|
|
} catch (error) {
|
||
|
|
console.error("테이블 목록 조회 오류:", error);
|
||
|
|
return res.status(500).json({
|
||
|
|
success: false,
|
||
|
|
message: "서버 내부 오류가 발생했습니다.",
|
||
|
|
error: error instanceof Error ? error.message : "알 수 없는 오류",
|
||
|
|
});
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 특정 테이블의 컬럼 정보 조회
|
||
|
|
* 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 connectionType = req.params.type as 'internal' | 'external';
|
||
|
|
const connectionId = req.params.id ? parseInt(req.params.id) : undefined;
|
||
|
|
const tableName = req.params.tableName;
|
||
|
|
|
||
|
|
if (connectionType !== 'internal' && connectionType !== 'external') {
|
||
|
|
return res.status(400).json({
|
||
|
|
success: false,
|
||
|
|
message: "유효하지 않은 커넥션 타입입니다. (internal 또는 external)",
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
if (connectionType === 'external' && (!connectionId || isNaN(connectionId))) {
|
||
|
|
return res.status(400).json({
|
||
|
|
success: false,
|
||
|
|
message: "외부 커넥션의 경우 유효한 커넥션 ID가 필요합니다.",
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!tableName) {
|
||
|
|
return res.status(400).json({
|
||
|
|
success: false,
|
||
|
|
message: "테이블명이 필요합니다.",
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
const result = await BatchService.getTableColumns(
|
||
|
|
connectionType,
|
||
|
|
tableName,
|
||
|
|
connectionId
|
||
|
|
);
|
||
|
|
|
||
|
|
if (result.success) {
|
||
|
|
return res.status(200).json(result);
|
||
|
|
} else {
|
||
|
|
return res.status(400).json(result);
|
||
|
|
}
|
||
|
|
} catch (error) {
|
||
|
|
console.error("컬럼 정보 조회 오류:", error);
|
||
|
|
return res.status(500).json({
|
||
|
|
success: false,
|
||
|
|
message: "서버 내부 오류가 발생했습니다.",
|
||
|
|
error: error instanceof Error ? error.message : "알 수 없는 오류",
|
||
|
|
});
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|