한글뷰어 기능수정
This commit is contained in:
@@ -2581,6 +2581,64 @@ exports.uploadData = async (req, res, next) => {
|
||||
let insertLogResult = await insertLog(params);
|
||||
if (insertLogResult.message == 'insertLog_success') {
|
||||
|
||||
// PPT/PPTX 파일 업로드 즉시 PDF 변환 처리
|
||||
for (let i = 0; i < insertDataResult.rows.length; i++) {
|
||||
try {
|
||||
let row = insertDataResult.rows[i];
|
||||
let resourcePath = params.resourcePathArr[i];
|
||||
let ext = (resourcePath.split('.').pop()).replace('.', '').toLowerCase();
|
||||
|
||||
if (['ppt', 'pptx'].includes(ext)) {
|
||||
let dataId = row.data_id;
|
||||
let objectKey = params.objectKeyArr[i];
|
||||
let storageType = params.storageType;
|
||||
let userInfoString = params.userInfoString;
|
||||
let userIp = req.ip;
|
||||
let bucket = projectId;
|
||||
|
||||
let command = new GetObjectCommand({
|
||||
Bucket: bucket,
|
||||
Key: objectKey,
|
||||
});
|
||||
|
||||
let url = await getSignedUrl(s3, command, { expiresIn: 60 * 60 * 6 }); // 유효시간 6시간
|
||||
|
||||
let initiator = `DEV_LOCAL_${JSON.parse(userInfoString).user_id}`;
|
||||
let type = 'archive';
|
||||
if (env == 'production') {
|
||||
if (deploymentType == 'ONPREMISE') initiator = 'HYHC_ONPREMISE';
|
||||
if (deploymentType == 'CLOUD') initiator = `AWS_CLOUD_${cloudType}`;
|
||||
}
|
||||
|
||||
const job = await convertPdfQueue.add(
|
||||
`'${initiator}'에서 문서를 PDF로 변환`,
|
||||
{ resourcePath, url, objectKey, bucket, storageType, dataId, projectId, userInfoString, userIp, initiator, type, serviceName }
|
||||
);
|
||||
|
||||
let resourcePathClean = resourcePath.startsWith('/') ? resourcePath.slice(1) : resourcePath;
|
||||
let pathArray = getPathArray(resourcePathClean);
|
||||
|
||||
convertingDataArr.push({
|
||||
dataId: dataId,
|
||||
resourcePath: resourcePath,
|
||||
depth1: pathArray[0],
|
||||
depth2: pathArray[1],
|
||||
depth3: pathArray[2],
|
||||
jobId: job.id
|
||||
});
|
||||
|
||||
// 변환 시작 소켓 전송
|
||||
let startEventData = { projectId: projectId, resourcePath: resourcePath, convertingDataArr: convertingDataArr };
|
||||
let io = getIo();
|
||||
io.emit('convert_start', startEventData);
|
||||
|
||||
console.log(`[PPT Auto-Convert] queued job ${job.id} for dataId ${dataId} (${resourcePath})`);
|
||||
}
|
||||
} catch (autoErr) {
|
||||
console.error(`[PPT Auto-Convert Failed] index ${i}:`, autoErr);
|
||||
}
|
||||
}
|
||||
|
||||
let resultData = {
|
||||
message: 'uploadData_success',
|
||||
projectId: projectId,
|
||||
@@ -2881,8 +2939,81 @@ exports.removeTarget = async(req, res) => {
|
||||
let permission = JSON.parse(params.userInfoString).permission;
|
||||
let depth = getDepth(params.resourcePathArr[0]);
|
||||
let isRecycleBinModal = params.isRecycleBinModal;
|
||||
const isExpiredFolder = params.isExpiredFolder === true;
|
||||
|
||||
if (!isRecycleBinModal && (depth == 1 && permission < 191) || (depth >= 2 && permission < 7)) {
|
||||
if (isExpiredFolder) {
|
||||
// 자동 기한 만료 삭제의 경우 안전 검증
|
||||
if (depth !== 3 || params.dataType !== 'folder') {
|
||||
return res.status(400).json({
|
||||
message: 'removeTarget_failed',
|
||||
error: '보존 정책 자동 삭제는 3단계 폴더만 대상이 될 수 있습니다.'
|
||||
});
|
||||
}
|
||||
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
// 1. 최신 시스템 정책 조회
|
||||
const policyRes = await client.query("SELECT * FROM ver4.tb_system_policy WHERE policy_key = 'GLOBAL_DELETE_POLICY'");
|
||||
if (policyRes.rows.length === 0 || !policyRes.rows[0].is_active) {
|
||||
return res.status(400).json({
|
||||
message: 'removeTarget_failed',
|
||||
error: '자동 삭제 정책이 비활성화 상태입니다.'
|
||||
});
|
||||
}
|
||||
const { limit_file_count, limit_days } = policyRes.rows[0];
|
||||
|
||||
// 2. 해당 폴더의 실제 정보 조회 (최종 활동 시각 확인)
|
||||
const resourcePath = params.resourcePathArr[0];
|
||||
const projectId = req.baseUrl.split('/')[1];
|
||||
const folderQuery = `
|
||||
SELECT last_folder_act_date
|
||||
FROM ver4.${tbData}
|
||||
WHERE project_id = $1 AND is_folder = true AND data_depth = 3 AND is_removed = false
|
||||
AND path1 = $2 AND path2 = $3 AND path3 = $4;
|
||||
`;
|
||||
const folderRes = await client.query(folderQuery, [
|
||||
projectId,
|
||||
getPathSegment(resourcePath, 1),
|
||||
getPathSegment(resourcePath, 2),
|
||||
getPathSegment(resourcePath, 3)
|
||||
]);
|
||||
|
||||
if (folderRes.rows.length === 0) {
|
||||
return res.status(404).json({
|
||||
message: 'removeTarget_failed',
|
||||
error: '해당 폴더를 찾을 수 없거나 이미 삭제되었습니다.'
|
||||
});
|
||||
}
|
||||
|
||||
const lastFolderActDate = new Date(folderRes.rows[0].last_folder_act_date);
|
||||
const expiryDate = new Date(lastFolderActDate.getTime() + limit_days * 24 * 60 * 60 * 1000);
|
||||
if (expiryDate > new Date()) {
|
||||
return res.status(400).json({
|
||||
message: 'removeTarget_failed',
|
||||
error: `해당 폴더는 아직 만료 기한이 지나지 않았습니다. (남은 기한 검증 실패)`
|
||||
});
|
||||
}
|
||||
|
||||
// 3. 하위 파일 개수 계산
|
||||
const filesCount = await getFilesCount(projectId, params.storageType || 'ONPREMISE', resourcePath);
|
||||
if (Number(filesCount) >= limit_file_count) {
|
||||
return res.status(400).json({
|
||||
message: 'removeTarget_failed',
|
||||
error: `해당 폴더의 파일 개수가 기준(${limit_file_count}개) 이상입니다. (파일 개수 검증 실패)`
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("isExpiredFolder verification error:", err);
|
||||
return res.status(500).json({
|
||||
message: 'removeTarget_failed',
|
||||
error: '만료 폴더 검증 처리 중 오류가 발생했습니다.'
|
||||
});
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
}
|
||||
|
||||
if (!isExpiredFolder && !isRecycleBinModal && ((depth == 1 && permission < 191) || (depth >= 2 && permission < 7))) {
|
||||
return res.status(200).json({
|
||||
message: 'removeTarget_failed_permission',
|
||||
});
|
||||
@@ -3221,7 +3352,7 @@ exports.addConvetPdfLog = async(req, res) => {
|
||||
exports.removeConvertingData = async(req, res) => {
|
||||
const projectId = req.baseUrl.split('/')[1];
|
||||
let { params } = req.body;
|
||||
let { resourcePath, dataId, userInfoString } = params;
|
||||
let { resourcePath, dataId, userInfoString, stdout } = params;
|
||||
|
||||
//// 배열에서 파일 정보 삭제
|
||||
convertingDataArr = convertingDataArr.filter(data => data.dataId !== dataId);
|
||||
@@ -3238,7 +3369,8 @@ exports.removeConvertingData = async(req, res) => {
|
||||
convertingDataArr: convertingDataArr,
|
||||
resourcePath: resourcePath,
|
||||
dataId: dataId,
|
||||
userInfoString: userInfoString
|
||||
userInfoString: userInfoString,
|
||||
stdout: stdout || ''
|
||||
};
|
||||
|
||||
let io = getIo();
|
||||
@@ -4363,6 +4495,7 @@ async function updateThumbnailInfoAction(projectId, params) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 삭제예정(2025.10.31): 이호성
|
||||
// exports.get3dViewerThumbUrl = async(req, res, next) => {
|
||||
// const dataId = req.query.dataId;
|
||||
|
||||
Reference in New Issue
Block a user