Compare commits
2 Commits
561d9cb855
...
c0f2fbbd88
| Author | SHA1 | Date |
|---|---|---|
|
|
c0f2fbbd88 | |
|
|
c333a9fd9d |
|
|
@ -461,12 +461,13 @@ export class CommonCodeController {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 카테고리 중복 검사
|
* 카테고리 중복 검사 (회사별)
|
||||||
* GET /api/common-codes/categories/check-duplicate?field=categoryCode&value=USER_STATUS&excludeCode=OLD_CODE
|
* GET /api/common-codes/categories/check-duplicate?field=categoryCode&value=USER_STATUS&excludeCode=OLD_CODE
|
||||||
*/
|
*/
|
||||||
async checkCategoryDuplicate(req: AuthenticatedRequest, res: Response) {
|
async checkCategoryDuplicate(req: AuthenticatedRequest, res: Response) {
|
||||||
try {
|
try {
|
||||||
const { field, value, excludeCode } = req.query;
|
const { field, value, excludeCode } = req.query;
|
||||||
|
const userCompanyCode = req.user?.companyCode;
|
||||||
|
|
||||||
// 입력값 검증
|
// 입력값 검증
|
||||||
if (!field || !value) {
|
if (!field || !value) {
|
||||||
|
|
@ -488,7 +489,8 @@ export class CommonCodeController {
|
||||||
const result = await this.commonCodeService.checkCategoryDuplicate(
|
const result = await this.commonCodeService.checkCategoryDuplicate(
|
||||||
field as "categoryCode" | "categoryName" | "categoryNameEng",
|
field as "categoryCode" | "categoryName" | "categoryNameEng",
|
||||||
value as string,
|
value as string,
|
||||||
excludeCode as string
|
excludeCode as string,
|
||||||
|
userCompanyCode
|
||||||
);
|
);
|
||||||
|
|
||||||
return res.json({
|
return res.json({
|
||||||
|
|
@ -511,13 +513,14 @@ export class CommonCodeController {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 코드 중복 검사
|
* 코드 중복 검사 (회사별)
|
||||||
* GET /api/common-codes/categories/:categoryCode/codes/check-duplicate?field=codeValue&value=ACTIVE&excludeCode=OLD_CODE
|
* GET /api/common-codes/categories/:categoryCode/codes/check-duplicate?field=codeValue&value=ACTIVE&excludeCode=OLD_CODE
|
||||||
*/
|
*/
|
||||||
async checkCodeDuplicate(req: AuthenticatedRequest, res: Response) {
|
async checkCodeDuplicate(req: AuthenticatedRequest, res: Response) {
|
||||||
try {
|
try {
|
||||||
const { categoryCode } = req.params;
|
const { categoryCode } = req.params;
|
||||||
const { field, value, excludeCode } = req.query;
|
const { field, value, excludeCode } = req.query;
|
||||||
|
const userCompanyCode = req.user?.companyCode;
|
||||||
|
|
||||||
// 입력값 검증
|
// 입력값 검증
|
||||||
if (!field || !value) {
|
if (!field || !value) {
|
||||||
|
|
@ -540,7 +543,8 @@ export class CommonCodeController {
|
||||||
categoryCode,
|
categoryCode,
|
||||||
field as "codeValue" | "codeName" | "codeNameEng",
|
field as "codeValue" | "codeName" | "codeNameEng",
|
||||||
value as string,
|
value as string,
|
||||||
excludeCode as string
|
excludeCode as string,
|
||||||
|
userCompanyCode
|
||||||
);
|
);
|
||||||
|
|
||||||
return res.json({
|
return res.json({
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,10 @@ router.get(
|
||||||
filter,
|
filter,
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = await ExternalDbConnectionService.getConnections(filter);
|
const result = await ExternalDbConnectionService.getConnections(
|
||||||
|
filter,
|
||||||
|
userCompanyCode
|
||||||
|
);
|
||||||
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
return res.status(200).json(result);
|
return res.status(200).json(result);
|
||||||
|
|
@ -319,7 +322,12 @@ router.delete(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await ExternalDbConnectionService.deleteConnection(id);
|
const userCompanyCode = req.user?.companyCode;
|
||||||
|
|
||||||
|
const result = await ExternalDbConnectionService.deleteConnection(
|
||||||
|
id,
|
||||||
|
userCompanyCode
|
||||||
|
);
|
||||||
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
return res.status(200).json(result);
|
return res.status(200).json(result);
|
||||||
|
|
@ -517,7 +525,10 @@ router.get(
|
||||||
});
|
});
|
||||||
|
|
||||||
const externalConnections =
|
const externalConnections =
|
||||||
await ExternalDbConnectionService.getConnections(filter);
|
await ExternalDbConnectionService.getConnections(
|
||||||
|
filter,
|
||||||
|
userCompanyCode
|
||||||
|
);
|
||||||
|
|
||||||
if (!externalConnections.success) {
|
if (!externalConnections.success) {
|
||||||
return res.status(400).json(externalConnections);
|
return res.status(400).json(externalConnections);
|
||||||
|
|
|
||||||
|
|
@ -29,8 +29,12 @@ router.get(
|
||||||
company_code: req.query.company_code as string,
|
company_code: req.query.company_code as string,
|
||||||
};
|
};
|
||||||
|
|
||||||
const result =
|
const userCompanyCode = req.user?.companyCode;
|
||||||
await ExternalRestApiConnectionService.getConnections(filter);
|
|
||||||
|
const result = await ExternalRestApiConnectionService.getConnections(
|
||||||
|
filter,
|
||||||
|
userCompanyCode
|
||||||
|
);
|
||||||
|
|
||||||
return res.status(result.success ? 200 : 400).json(result);
|
return res.status(result.success ? 200 : 400).json(result);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
@ -62,8 +66,12 @@ router.get(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const result =
|
const userCompanyCode = req.user?.companyCode;
|
||||||
await ExternalRestApiConnectionService.getConnectionById(id);
|
|
||||||
|
const result = await ExternalRestApiConnectionService.getConnectionById(
|
||||||
|
id,
|
||||||
|
userCompanyCode
|
||||||
|
);
|
||||||
|
|
||||||
return res.status(result.success ? 200 : 404).json(result);
|
return res.status(result.success ? 200 : 404).json(result);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
@ -129,9 +137,12 @@ router.put(
|
||||||
updated_by: req.user?.userId || "system",
|
updated_by: req.user?.userId || "system",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const userCompanyCode = req.user?.companyCode;
|
||||||
|
|
||||||
const result = await ExternalRestApiConnectionService.updateConnection(
|
const result = await ExternalRestApiConnectionService.updateConnection(
|
||||||
id,
|
id,
|
||||||
data
|
data,
|
||||||
|
userCompanyCode
|
||||||
);
|
);
|
||||||
|
|
||||||
return res.status(result.success ? 200 : 400).json(result);
|
return res.status(result.success ? 200 : 400).json(result);
|
||||||
|
|
@ -164,8 +175,12 @@ router.delete(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const result =
|
const userCompanyCode = req.user?.companyCode;
|
||||||
await ExternalRestApiConnectionService.deleteConnection(id);
|
|
||||||
|
const result = await ExternalRestApiConnectionService.deleteConnection(
|
||||||
|
id,
|
||||||
|
userCompanyCode
|
||||||
|
);
|
||||||
|
|
||||||
return res.status(result.success ? 200 : 404).json(result);
|
return res.status(result.success ? 200 : 404).json(result);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
|
||||||
|
|
@ -604,12 +604,13 @@ export class CommonCodeService {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 카테고리 중복 검사
|
* 카테고리 중복 검사 (회사별)
|
||||||
*/
|
*/
|
||||||
async checkCategoryDuplicate(
|
async checkCategoryDuplicate(
|
||||||
field: "categoryCode" | "categoryName" | "categoryNameEng",
|
field: "categoryCode" | "categoryName" | "categoryNameEng",
|
||||||
value: string,
|
value: string,
|
||||||
excludeCategoryCode?: string
|
excludeCategoryCode?: string,
|
||||||
|
userCompanyCode?: string
|
||||||
): Promise<{ isDuplicate: boolean; message: string }> {
|
): Promise<{ isDuplicate: boolean; message: string }> {
|
||||||
try {
|
try {
|
||||||
if (!value || !value.trim()) {
|
if (!value || !value.trim()) {
|
||||||
|
|
@ -655,6 +656,12 @@ export class CommonCodeService {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 회사별 필터링 (최고 관리자가 아닌 경우)
|
||||||
|
if (userCompanyCode && userCompanyCode !== "*") {
|
||||||
|
sql += ` AND company_code = $${paramIndex++}`;
|
||||||
|
values.push(userCompanyCode);
|
||||||
|
}
|
||||||
|
|
||||||
// 수정 시 자기 자신 제외
|
// 수정 시 자기 자신 제외
|
||||||
if (excludeCategoryCode) {
|
if (excludeCategoryCode) {
|
||||||
sql += ` AND category_code != $${paramIndex++}`;
|
sql += ` AND category_code != $${paramIndex++}`;
|
||||||
|
|
@ -675,6 +682,10 @@ export class CommonCodeService {
|
||||||
categoryNameEng: "카테고리 영문명",
|
categoryNameEng: "카테고리 영문명",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
logger.info(
|
||||||
|
`카테고리 중복 검사: ${field}=${value}, 회사=${userCompanyCode}, 중복=${isDuplicate}`
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
isDuplicate,
|
isDuplicate,
|
||||||
message: isDuplicate
|
message: isDuplicate
|
||||||
|
|
@ -688,13 +699,14 @@ export class CommonCodeService {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 코드 중복 검사
|
* 코드 중복 검사 (회사별)
|
||||||
*/
|
*/
|
||||||
async checkCodeDuplicate(
|
async checkCodeDuplicate(
|
||||||
categoryCode: string,
|
categoryCode: string,
|
||||||
field: "codeValue" | "codeName" | "codeNameEng",
|
field: "codeValue" | "codeName" | "codeNameEng",
|
||||||
value: string,
|
value: string,
|
||||||
excludeCodeValue?: string
|
excludeCodeValue?: string,
|
||||||
|
userCompanyCode?: string
|
||||||
): Promise<{ isDuplicate: boolean; message: string }> {
|
): Promise<{ isDuplicate: boolean; message: string }> {
|
||||||
try {
|
try {
|
||||||
if (!value || !value.trim()) {
|
if (!value || !value.trim()) {
|
||||||
|
|
@ -743,6 +755,12 @@ export class CommonCodeService {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 회사별 필터링 (최고 관리자가 아닌 경우)
|
||||||
|
if (userCompanyCode && userCompanyCode !== "*") {
|
||||||
|
sql += ` AND company_code = $${paramIndex++}`;
|
||||||
|
values.push(userCompanyCode);
|
||||||
|
}
|
||||||
|
|
||||||
// 수정 시 자기 자신 제외
|
// 수정 시 자기 자신 제외
|
||||||
if (excludeCodeValue) {
|
if (excludeCodeValue) {
|
||||||
sql += ` AND code_value != $${paramIndex++}`;
|
sql += ` AND code_value != $${paramIndex++}`;
|
||||||
|
|
@ -760,6 +778,10 @@ export class CommonCodeService {
|
||||||
codeNameEng: "코드 영문명",
|
codeNameEng: "코드 영문명",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
logger.info(
|
||||||
|
`코드 중복 검사: ${categoryCode}.${field}=${value}, 회사=${userCompanyCode}, 중복=${isDuplicate}`
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
isDuplicate,
|
isDuplicate,
|
||||||
message: isDuplicate
|
message: isDuplicate
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,8 @@ export class ExternalDbConnectionService {
|
||||||
* 외부 DB 연결 목록 조회
|
* 외부 DB 연결 목록 조회
|
||||||
*/
|
*/
|
||||||
static async getConnections(
|
static async getConnections(
|
||||||
filter: ExternalDbConnectionFilter
|
filter: ExternalDbConnectionFilter,
|
||||||
|
userCompanyCode?: string
|
||||||
): Promise<ApiResponse<ExternalDbConnection[]>> {
|
): Promise<ApiResponse<ExternalDbConnection[]>> {
|
||||||
try {
|
try {
|
||||||
// WHERE 조건 동적 생성
|
// WHERE 조건 동적 생성
|
||||||
|
|
@ -25,6 +26,26 @@ export class ExternalDbConnectionService {
|
||||||
const params: any[] = [];
|
const params: any[] = [];
|
||||||
let paramIndex = 1;
|
let paramIndex = 1;
|
||||||
|
|
||||||
|
// 회사별 필터링 (최고 관리자가 아닌 경우 필수)
|
||||||
|
if (userCompanyCode && userCompanyCode !== "*") {
|
||||||
|
whereConditions.push(`company_code = $${paramIndex++}`);
|
||||||
|
params.push(userCompanyCode);
|
||||||
|
logger.info(`회사별 외부 DB 연결 필터링: ${userCompanyCode}`);
|
||||||
|
} else if (userCompanyCode === "*") {
|
||||||
|
logger.info(`최고 관리자: 모든 외부 DB 연결 조회`);
|
||||||
|
// 필터가 있으면 적용
|
||||||
|
if (filter.company_code) {
|
||||||
|
whereConditions.push(`company_code = $${paramIndex++}`);
|
||||||
|
params.push(filter.company_code);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// userCompanyCode가 없는 경우 (하위 호환성)
|
||||||
|
if (filter.company_code) {
|
||||||
|
whereConditions.push(`company_code = $${paramIndex++}`);
|
||||||
|
params.push(filter.company_code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 필터 조건 적용
|
// 필터 조건 적용
|
||||||
if (filter.db_type) {
|
if (filter.db_type) {
|
||||||
whereConditions.push(`db_type = $${paramIndex++}`);
|
whereConditions.push(`db_type = $${paramIndex++}`);
|
||||||
|
|
@ -36,11 +57,6 @@ export class ExternalDbConnectionService {
|
||||||
params.push(filter.is_active);
|
params.push(filter.is_active);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filter.company_code) {
|
|
||||||
whereConditions.push(`company_code = $${paramIndex++}`);
|
|
||||||
params.push(filter.company_code);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 검색 조건 적용 (연결명 또는 설명에서 검색)
|
// 검색 조건 적용 (연결명 또는 설명에서 검색)
|
||||||
if (filter.search && filter.search.trim()) {
|
if (filter.search && filter.search.trim()) {
|
||||||
whereConditions.push(
|
whereConditions.push(
|
||||||
|
|
@ -496,23 +512,36 @@ export class ExternalDbConnectionService {
|
||||||
/**
|
/**
|
||||||
* 외부 DB 연결 삭제 (물리 삭제)
|
* 외부 DB 연결 삭제 (물리 삭제)
|
||||||
*/
|
*/
|
||||||
static async deleteConnection(id: number): Promise<ApiResponse<void>> {
|
static async deleteConnection(
|
||||||
|
id: number,
|
||||||
|
userCompanyCode?: string
|
||||||
|
): Promise<ApiResponse<void>> {
|
||||||
try {
|
try {
|
||||||
const existingConnection = await queryOne(
|
let selectQuery = `SELECT id FROM external_db_connections WHERE id = $1`;
|
||||||
`SELECT id FROM external_db_connections WHERE id = $1`,
|
const selectParams: any[] = [id];
|
||||||
[id]
|
|
||||||
);
|
// 회사별 필터링 (최고 관리자가 아닌 경우)
|
||||||
|
if (userCompanyCode && userCompanyCode !== "*") {
|
||||||
|
selectQuery += ` AND company_code = $2`;
|
||||||
|
selectParams.push(userCompanyCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
const existingConnection = await queryOne(selectQuery, selectParams);
|
||||||
|
|
||||||
if (!existingConnection) {
|
if (!existingConnection) {
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
message: "해당 연결 설정을 찾을 수 없습니다.",
|
message: "해당 연결 설정을 찾을 수 없거나 권한이 없습니다.",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// 물리 삭제 (실제 데이터 삭제)
|
// 물리 삭제 (실제 데이터 삭제)
|
||||||
await query(`DELETE FROM external_db_connections WHERE id = $1`, [id]);
|
await query(`DELETE FROM external_db_connections WHERE id = $1`, [id]);
|
||||||
|
|
||||||
|
logger.info(
|
||||||
|
`외부 DB 연결 삭제: ID ${id} (회사: ${userCompanyCode || "전체"})`
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
message: "연결 설정이 삭제되었습니다.",
|
message: "연결 설정이 삭제되었습니다.",
|
||||||
|
|
@ -747,8 +776,11 @@ export class ExternalDbConnectionService {
|
||||||
try {
|
try {
|
||||||
// 보안 검증: SELECT 쿼리만 허용
|
// 보안 검증: SELECT 쿼리만 허용
|
||||||
const trimmedQuery = query.trim().toUpperCase();
|
const trimmedQuery = query.trim().toUpperCase();
|
||||||
if (!trimmedQuery.startsWith('SELECT')) {
|
if (!trimmedQuery.startsWith("SELECT")) {
|
||||||
console.log("보안 오류: SELECT가 아닌 쿼리 시도:", { id, query: query.substring(0, 100) });
|
console.log("보안 오류: SELECT가 아닌 쿼리 시도:", {
|
||||||
|
id,
|
||||||
|
query: query.substring(0, 100),
|
||||||
|
});
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
message: "외부 데이터베이스에서는 SELECT 쿼리만 실행할 수 있습니다.",
|
message: "외부 데이터베이스에서는 SELECT 쿼리만 실행할 수 있습니다.",
|
||||||
|
|
@ -756,16 +788,32 @@ export class ExternalDbConnectionService {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 위험한 키워드 검사
|
// 위험한 키워드 검사
|
||||||
const dangerousKeywords = ['INSERT', 'UPDATE', 'DELETE', 'DROP', 'CREATE', 'ALTER', 'TRUNCATE', 'EXEC', 'EXECUTE', 'CALL', 'MERGE'];
|
const dangerousKeywords = [
|
||||||
const hasDangerousKeyword = dangerousKeywords.some(keyword =>
|
"INSERT",
|
||||||
|
"UPDATE",
|
||||||
|
"DELETE",
|
||||||
|
"DROP",
|
||||||
|
"CREATE",
|
||||||
|
"ALTER",
|
||||||
|
"TRUNCATE",
|
||||||
|
"EXEC",
|
||||||
|
"EXECUTE",
|
||||||
|
"CALL",
|
||||||
|
"MERGE",
|
||||||
|
];
|
||||||
|
const hasDangerousKeyword = dangerousKeywords.some((keyword) =>
|
||||||
trimmedQuery.includes(keyword)
|
trimmedQuery.includes(keyword)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (hasDangerousKeyword) {
|
if (hasDangerousKeyword) {
|
||||||
console.log("보안 오류: 위험한 키워드 포함 쿼리 시도:", { id, query: query.substring(0, 100) });
|
console.log("보안 오류: 위험한 키워드 포함 쿼리 시도:", {
|
||||||
|
id,
|
||||||
|
query: query.substring(0, 100),
|
||||||
|
});
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
message: "데이터를 변경하거나 삭제하는 쿼리는 허용되지 않습니다. SELECT 쿼리만 사용해주세요.",
|
message:
|
||||||
|
"데이터를 변경하거나 삭제하는 쿼리는 허용되지 않습니다. SELECT 쿼리만 사용해주세요.",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,8 @@ export class ExternalRestApiConnectionService {
|
||||||
* REST API 연결 목록 조회
|
* REST API 연결 목록 조회
|
||||||
*/
|
*/
|
||||||
static async getConnections(
|
static async getConnections(
|
||||||
filter: ExternalRestApiConnectionFilter = {}
|
filter: ExternalRestApiConnectionFilter = {},
|
||||||
|
userCompanyCode?: string
|
||||||
): Promise<ApiResponse<ExternalRestApiConnection[]>> {
|
): Promise<ApiResponse<ExternalRestApiConnection[]>> {
|
||||||
try {
|
try {
|
||||||
let query = `
|
let query = `
|
||||||
|
|
@ -39,11 +40,27 @@ export class ExternalRestApiConnectionService {
|
||||||
const params: any[] = [];
|
const params: any[] = [];
|
||||||
let paramIndex = 1;
|
let paramIndex = 1;
|
||||||
|
|
||||||
// 회사 코드 필터
|
// 회사별 필터링 (최고 관리자가 아닌 경우 필수)
|
||||||
if (filter.company_code) {
|
if (userCompanyCode && userCompanyCode !== "*") {
|
||||||
query += ` AND company_code = $${paramIndex}`;
|
query += ` AND company_code = $${paramIndex}`;
|
||||||
params.push(filter.company_code);
|
params.push(userCompanyCode);
|
||||||
paramIndex++;
|
paramIndex++;
|
||||||
|
logger.info(`회사별 REST API 연결 필터링: ${userCompanyCode}`);
|
||||||
|
} else if (userCompanyCode === "*") {
|
||||||
|
logger.info(`최고 관리자: 모든 REST API 연결 조회`);
|
||||||
|
// 필터가 있으면 적용
|
||||||
|
if (filter.company_code) {
|
||||||
|
query += ` AND company_code = $${paramIndex}`;
|
||||||
|
params.push(filter.company_code);
|
||||||
|
paramIndex++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// userCompanyCode가 없는 경우 (하위 호환성)
|
||||||
|
if (filter.company_code) {
|
||||||
|
query += ` AND company_code = $${paramIndex}`;
|
||||||
|
params.push(filter.company_code);
|
||||||
|
paramIndex++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 활성 상태 필터
|
// 활성 상태 필터
|
||||||
|
|
@ -105,10 +122,11 @@ export class ExternalRestApiConnectionService {
|
||||||
* REST API 연결 상세 조회
|
* REST API 연결 상세 조회
|
||||||
*/
|
*/
|
||||||
static async getConnectionById(
|
static async getConnectionById(
|
||||||
id: number
|
id: number,
|
||||||
|
userCompanyCode?: string
|
||||||
): Promise<ApiResponse<ExternalRestApiConnection>> {
|
): Promise<ApiResponse<ExternalRestApiConnection>> {
|
||||||
try {
|
try {
|
||||||
const query = `
|
let query = `
|
||||||
SELECT
|
SELECT
|
||||||
id, connection_name, description, base_url, default_headers,
|
id, connection_name, description, base_url, default_headers,
|
||||||
auth_type, auth_config, timeout, retry_count, retry_delay,
|
auth_type, auth_config, timeout, retry_count, retry_delay,
|
||||||
|
|
@ -118,12 +136,20 @@ export class ExternalRestApiConnectionService {
|
||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const result: QueryResult<any> = await pool.query(query, [id]);
|
const params: any[] = [id];
|
||||||
|
|
||||||
|
// 회사별 필터링 (최고 관리자가 아닌 경우)
|
||||||
|
if (userCompanyCode && userCompanyCode !== "*") {
|
||||||
|
query += ` AND company_code = $2`;
|
||||||
|
params.push(userCompanyCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
const result: QueryResult<any> = await pool.query(query, params);
|
||||||
|
|
||||||
if (result.rows.length === 0) {
|
if (result.rows.length === 0) {
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
message: "연결을 찾을 수 없습니다.",
|
message: "연결을 찾을 수 없거나 권한이 없습니다.",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -225,11 +251,12 @@ export class ExternalRestApiConnectionService {
|
||||||
*/
|
*/
|
||||||
static async updateConnection(
|
static async updateConnection(
|
||||||
id: number,
|
id: number,
|
||||||
data: Partial<ExternalRestApiConnection>
|
data: Partial<ExternalRestApiConnection>,
|
||||||
|
userCompanyCode?: string
|
||||||
): Promise<ApiResponse<ExternalRestApiConnection>> {
|
): Promise<ApiResponse<ExternalRestApiConnection>> {
|
||||||
try {
|
try {
|
||||||
// 기존 연결 확인
|
// 기존 연결 확인 (회사 코드로 권한 체크)
|
||||||
const existing = await this.getConnectionById(id);
|
const existing = await this.getConnectionById(id, userCompanyCode);
|
||||||
if (!existing.success) {
|
if (!existing.success) {
|
||||||
return existing;
|
return existing;
|
||||||
}
|
}
|
||||||
|
|
@ -353,24 +380,38 @@ export class ExternalRestApiConnectionService {
|
||||||
/**
|
/**
|
||||||
* REST API 연결 삭제
|
* REST API 연결 삭제
|
||||||
*/
|
*/
|
||||||
static async deleteConnection(id: number): Promise<ApiResponse<void>> {
|
static async deleteConnection(
|
||||||
|
id: number,
|
||||||
|
userCompanyCode?: string
|
||||||
|
): Promise<ApiResponse<void>> {
|
||||||
try {
|
try {
|
||||||
const query = `
|
let query = `
|
||||||
DELETE FROM external_rest_api_connections
|
DELETE FROM external_rest_api_connections
|
||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
RETURNING connection_name
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const result: QueryResult<any> = await pool.query(query, [id]);
|
const params: any[] = [id];
|
||||||
|
|
||||||
|
// 회사별 필터링 (최고 관리자가 아닌 경우)
|
||||||
|
if (userCompanyCode && userCompanyCode !== "*") {
|
||||||
|
query += ` AND company_code = $2`;
|
||||||
|
params.push(userCompanyCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
query += ` RETURNING connection_name`;
|
||||||
|
|
||||||
|
const result: QueryResult<any> = await pool.query(query, params);
|
||||||
|
|
||||||
if (result.rows.length === 0) {
|
if (result.rows.length === 0) {
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
message: "연결을 찾을 수 없습니다.",
|
message: "연결을 찾을 수 없거나 권한이 없습니다.",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info(`REST API 연결 삭제 성공: ${result.rows[0].connection_name}`);
|
logger.info(
|
||||||
|
`REST API 연결 삭제 성공: ${result.rows[0].connection_name} (회사: ${userCompanyCode || "전체"})`
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue