@channel.io/be-user-chat-mcp
Version:
Backend UserChat Model Context Protocol server for Channel.io
77 lines • 4 kB
JavaScript
import { executeRawRedashQuery } from "../services/redash.service.js";
// --- Type Definitions ---
export var Action;
(function (Action) {
Action["CREATE"] = "create";
Action["UPDATE"] = "update";
Action["DELETE"] = "delete";
})(Action = Action || (Action = {}));
// --- Constants ---
// Use hard-coded default values instead of environment variables
const REDASH_DATA_SOURCE_ID_CHANNEL_PROD_PSQL = "1";
const TABLE_CHANGE_LOGS = "change_logs";
// --- Utility Functions ---
/**
* 엔티티 타입과 ID 문자열의 유효성을 검사합니다. (간단한 예시)
* 실제 환경에서는 더 엄격한 검증이 필요할 수 있습니다.
*/
function validateEntityParameters(entityType, entityId, context) {
if (!entityType ||
typeof entityType !== "string" ||
entityType.length === 0 ||
entityType.length > 255) {
console.error(`Invalid entityType format detected in ${context}: ${entityType}`);
throw new Error(`Invalid entityType format provided for ${context}.`);
}
if (!entityId ||
typeof entityId !== "string" ||
entityId.length === 0 ||
entityId.length > 255) {
console.error(`Invalid entityId format detected in ${context}: ${entityId}`);
throw new Error(`Invalid entityId format provided for ${context}.`);
}
// SQL 인젝션 방지를 위해 매우 기본적인 필터링 (실제로는 부족할 수 있음)
// 실제로는 ORM이나 매개변수화된 쿼리를 사용하는 것이 훨씬 안전합니다.
if (/[^a-zA-Z0-9_:-]/.test(entityType) || /[^a-zA-Z0-9_:-]/.test(entityId)) {
console.error(`Potentially unsafe characters in entityType or entityId in ${context}. entityType: ${entityType}, entityId: ${entityId}`);
throw new Error(`Unsafe characters detected in entityType or entityId for ${context}.`);
}
}
// --- Data Fetching Functions ---
/**
* 주어진 entityType과 entityId에 해당하는 변경 로그들을 Redash를 통해 조회합니다.
* 생성 날짜(createdAt) 기준 내림차순으로 정렬되며, 페이지네이션을 지원합니다.
* 쿼리 실패 시 에러를 발생시킵니다.
* @param entityType 엔티티 유형
* @param entityId 엔티티 ID
* @param since 페이지 번호 (1부터 시작, 기본값 1)
* @param context Optional RequestContext for HTTP transport.
* @returns 로그 목록과 다음 페이지 번호
*/
export async function getChangeLogsByEntity(entityType, entityId, since = 1, // 기본 페이지 1
context) {
const operationContext = `getChangeLogsByEntity (entityType: ${entityType}, entityId: ${entityId}, since: ${since})`;
validateEntityParameters(entityType, entityId, operationContext); // 입력값 검증
const pageSize = 10;
const offset = (since - 1) * pageSize;
// SQL 쿼리: SQL 인젝션에 매우 취약합니다.
// 프로덕션 환경에서는 반드시 매개변수화된 쿼리나 ORM을 사용해야 합니다.
const sql = `SELECT created_at, diff FROM ${TABLE_CHANGE_LOGS} WHERE entity_type = '${entityType}' AND entity_id = '${entityId}' ORDER BY created_at DESC LIMIT ${pageSize} OFFSET ${offset};`;
const dataSourceId = parseInt(REDASH_DATA_SOURCE_ID_CHANNEL_PROD_PSQL, 10);
if (isNaN(dataSourceId)) {
throw new Error(`Invalid REDASH_DATA_SOURCE_ID_PSQL: ${REDASH_DATA_SOURCE_ID_CHANNEL_PROD_PSQL}`);
}
try {
const results = await executeRawRedashQuery(dataSourceId, sql, operationContext, context);
let nextSince = undefined;
if (results.length === pageSize) {
nextSince = since + 1;
}
return { nextSince, changeLogs: results }; // 결과가 없으면 빈 배열과 undefined nextSince 반환
}
catch (error) {
console.error(`[ChangeLog Feature] Error in ${operationContext}:`, error);
throw error; // redash.service.ts에서 처리된 에러를 다시 throw
}
}
//# sourceMappingURL=change-log.repository.js.map