1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
|
'use server'
import fs from 'fs/promises'
import path from 'path'
import { NextResponse } from 'next/server'
/**
* 첨부 파일 다운로드를 위한 서버 액션
*
* @param filePath 파일의 상대 경로
* @returns 파일 내용(Base64 인코딩) 및 메타데이터를 포함한 객체
*/
export async function downloadFileAction(filePath: string) {
try {
// 보안: 파일 경로가 uploads 디렉토리 내에 있는지 확인
if (!filePath.startsWith('/uploads/') && !filePath.startsWith('uploads/')) {
return {
ok: false,
error: 'Invalid file path. Only files in the uploads directory can be downloaded.'
};
}
// 실제 서버 파일 시스템에서의 전체 경로 계산
// 참고: process.cwd()는 현재 실행 중인 프로세스의 작업 디렉토리를 반환합니다.
// 환경에 따라 public 폴더나 다른 위치를 기준으로 할 수도 있습니다.
const normalizedPath = filePath.startsWith('/') ? filePath.slice(1) : filePath;
const fullPath = path.join(process.cwd(), 'public', normalizedPath);
// 파일 존재 여부 확인
try {
await fs.access(fullPath);
} catch {
return { ok: false, error: 'File not found' };
}
// 파일 읽기
const fileBuffer = await fs.readFile(fullPath);
// 파일 통계 정보 가져오기
const stats = await fs.stat(fullPath);
// MIME 타입 추측
const extension = path.extname(fullPath).toLowerCase();
let mimeType = 'application/octet-stream'; // 기본값
// 일반적인 파일 타입에 대한 MIME 타입 매핑
const mimeTypes = {
'.pdf': 'application/pdf',
'.doc': 'application/msword',
'.docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'.xls': 'application/vnd.ms-excel',
'.xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'.png': 'image/png',
'.jpg': 'image/jpeg',
'.jpeg': 'image/jpeg',
'.gif': 'image/gif',
'.txt': 'text/plain',
};
if (extension in mimeTypes) {
mimeType = mimeTypes[extension];
}
// Base64로 인코딩하여 반환
return {
ok: true,
data: {
content: fileBuffer.toString('base64'),
fileName: path.basename(fullPath),
size: stats.size,
mimeType,
},
};
} catch (error) {
console.error('Download error:', error);
return {
ok: false,
error: error instanceof Error ? error.message : 'An unknown error occurred'
};
}
}
|