Initial commit - EENE Dashboard
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
84
backend/src/routes/files.ts
Normal file
84
backend/src/routes/files.ts
Normal file
@@ -0,0 +1,84 @@
|
||||
import { Router } from 'express';
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import { prisma } from '../lib/prisma';
|
||||
import { upload } from '../middleware/upload';
|
||||
import { AppError } from '../middleware/errorHandler';
|
||||
|
||||
const router = Router();
|
||||
|
||||
// POST /api/files/upload/:taskId — 파일 업로드
|
||||
router.post('/upload/:taskId', upload.single('file'), async (req, res, next) => {
|
||||
try {
|
||||
if (!req.file) throw new AppError(400, '파일이 없습니다.');
|
||||
const taskId = String(req.params.taskId);
|
||||
|
||||
const task = await prisma.task.findUnique({ where: { id: taskId } });
|
||||
if (!task) throw new AppError(404, '업무를 찾을 수 없습니다.');
|
||||
|
||||
const fileRecord = await prisma.file.create({
|
||||
data: {
|
||||
taskId,
|
||||
filename: req.file.filename,
|
||||
originalName: req.file.originalname,
|
||||
mimetype: req.file.mimetype,
|
||||
size: req.file.size,
|
||||
path: req.file.path,
|
||||
uploadedBy: (req.body as Record<string, string>).uploadedBy ?? 'system',
|
||||
},
|
||||
});
|
||||
|
||||
res.status(201).json(fileRecord);
|
||||
} catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
|
||||
// GET /api/files/:id/view — 파일 미리보기 (브라우저에서 바로 열기)
|
||||
router.get('/:id/view', async (req, res, next) => {
|
||||
try {
|
||||
const file = await prisma.file.findUnique({ where: { id: req.params.id } });
|
||||
if (!file) throw new AppError(404, '파일을 찾을 수 없습니다.');
|
||||
if (!fs.existsSync(file.path)) throw new AppError(404, '파일이 서버에 없습니다.');
|
||||
|
||||
res.setHeader('Content-Type', file.mimetype);
|
||||
res.setHeader('Content-Disposition', `inline; filename="${encodeURIComponent(file.originalName)}"`);
|
||||
fs.createReadStream(file.path).pipe(res);
|
||||
} catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
|
||||
// GET /api/files/:id/download — 파일 다운로드
|
||||
router.get('/:id/download', async (req, res, next) => {
|
||||
try {
|
||||
const file = await prisma.file.findUnique({ where: { id: req.params.id } });
|
||||
if (!file) throw new AppError(404, '파일을 찾을 수 없습니다.');
|
||||
if (!fs.existsSync(file.path)) throw new AppError(404, '파일이 서버에 없습니다.');
|
||||
|
||||
res.setHeader('Content-Disposition', `attachment; filename="${encodeURIComponent(file.originalName)}"`);
|
||||
res.download(file.path, file.originalName);
|
||||
} catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
|
||||
// DELETE /api/files/:id — 파일 삭제
|
||||
router.delete('/:id', async (req, res, next) => {
|
||||
try {
|
||||
const file = await prisma.file.findUnique({ where: { id: req.params.id } });
|
||||
if (!file) throw new AppError(404, '파일을 찾을 수 없습니다.');
|
||||
|
||||
// 실제 파일 삭제
|
||||
if (fs.existsSync(file.path)) {
|
||||
fs.unlinkSync(file.path);
|
||||
}
|
||||
|
||||
await prisma.file.delete({ where: { id: req.params.id } });
|
||||
res.status(204).send();
|
||||
} catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
Reference in New Issue
Block a user