117 lines
4.1 KiB
TypeScript
117 lines
4.1 KiB
TypeScript
import { BadRequestException, Body, Controller, Get, Post, UploadedFile, UseInterceptors, Logger } from "@nestjs/common";
|
|
import { AdminService } from "./admin.service";
|
|
import { FileInterceptor } from "@nestjs/platform-express";
|
|
import { basename, extname, join } from "path";
|
|
import { BaseResultDto } from "src/common/dto/base.result.dto";
|
|
import { diskStorage } from "multer";
|
|
|
|
import * as fs from 'fs/promises';
|
|
import { randomUUID } from "crypto";
|
|
import { tmpdir } from "os";
|
|
|
|
|
|
/**
|
|
※업로드 관련 기능 추후 공통화 처리 필요.
|
|
**/
|
|
const ALLOWED_EXTENSIONS = ['.xlsx', '.txt', '.csv', '.xls']; // 파일 업로드 허용 확장자
|
|
const ALLOWED_MIME_TYPES = [ // 파일 업로드 허용 MIME 타입
|
|
'text/plain',
|
|
// XLSX
|
|
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
// XLS (구형 + CSV도 섞여 나옴)
|
|
'application/vnd.ms-excel',
|
|
// CSV 계열
|
|
'text/csv',
|
|
'application/csv',
|
|
'text/plain',
|
|
// 한컴
|
|
'application/haansoftxls',
|
|
];
|
|
|
|
@Controller('admin')
|
|
export class AdminController {
|
|
constructor(private readonly adminService: AdminService) {}
|
|
|
|
private readonly logger = new Logger(AdminController.name);
|
|
|
|
@Get('dashboard')
|
|
getDashboard() {
|
|
return null;
|
|
}
|
|
|
|
|
|
|
|
|
|
@Post('batchUpload')
|
|
@UseInterceptors(FileInterceptor('file', {
|
|
storage: diskStorage({
|
|
destination: async (req, file, callback) => {
|
|
// 환경 변수가 없으면 시스템 임시 디렉터리 사용
|
|
const uploadDir = process.env.UPLOAD_DESTINATION
|
|
? join(process.env.UPLOAD_DESTINATION, 'tmp')
|
|
: join(tmpdir(), 'genome2025-uploads');
|
|
|
|
try {
|
|
// 디렉터리가 없으면 생성
|
|
await fs.mkdir(uploadDir, { recursive: true });
|
|
callback(null, uploadDir);
|
|
} catch (error) {
|
|
callback(error, null);
|
|
}
|
|
},
|
|
filename: (req, file, callback) => {
|
|
const ext = extname(file.originalname).toLowerCase();
|
|
callback(null, `${randomUUID()}-${Date.now()}${ext}`);
|
|
},
|
|
}),
|
|
fileFilter: (req, file, callback) => { // 파일 업로드 필터링
|
|
const ext = extname(file.originalname).toLowerCase();
|
|
const mime = file.mimetype;
|
|
|
|
if (!ALLOWED_EXTENSIONS.includes(ext)) { // 허용되지 않은 확장자 필터링
|
|
return callback(
|
|
new BadRequestException(`허용되지 않은 확장자: ${ext}`),
|
|
false,
|
|
);
|
|
}
|
|
|
|
if (!ALLOWED_MIME_TYPES.includes(mime)) { // 허용되지 않은 MIME 타입 필터링
|
|
return callback(
|
|
new BadRequestException(`허용되지 않은 MIME 타입: ${mime}`),
|
|
false,
|
|
);
|
|
}
|
|
|
|
callback(null, true);
|
|
}
|
|
}))
|
|
async batchUpload(@UploadedFile() file: Express.Multer.File, @Body('div') div: string) {
|
|
let divName = '';
|
|
try {
|
|
if (!file?.path){
|
|
throw new BadRequestException('파일 업로드 실패')
|
|
};
|
|
|
|
if (div === 'genome-result') { // 유전체 분석 결과(DGV)
|
|
divName = '유전체 분석 결과(DGV)';
|
|
await this.adminService.batchInsertGenomeResult(file);
|
|
}else if (div === 'snp-typing') { // 개체별 SNP 타이핑 결과(유전자 타이핑 결과)
|
|
divName = '개체별 SNP 타이핑 결과(유전자 타이핑 결과)';
|
|
await this.adminService.batchInsertSnpTyping(file);
|
|
}else if (div === 'mpt-result') { // MPT 분석결과(종합혈액화학검사결과서)
|
|
divName = 'MPT 분석결과(종합혈액화학검사결과서)';
|
|
await this.adminService.batchInsertMptResult(file);
|
|
}
|
|
// else if (div === 'animal-info') { // 소 정보 입력은 어디서 처리?
|
|
// divName = '소 정보 입력';
|
|
// return this.adminService.batchUploadAnimalInfo(file);
|
|
// }
|
|
return BaseResultDto.ok(`${divName} 파일 업로드 성공.\n데이터 입력 중...`, 'SUCCESS', 'OK');
|
|
} catch (error) {
|
|
return BaseResultDto.fail(`${divName} 파일 업로드 실패.\n${error.message}`, 'FAIL');
|
|
} finally {
|
|
await fs.unlink(file.path).catch(() => {}); // 파일 삭제
|
|
this.logger.log(`[batchUpload] ${divName} 파일 업로드 완료`);
|
|
}
|
|
}
|
|
} |