import express from 'express' import { searchSubstances, getSubstanceById, listAnalyses, getAnalysis, createAnalysis, updateAnalysisResult, deleteAnalysis } from './hnsService.js' import { isValidNumber } from '../middleware/security.js' import { requireAuth, requirePermission } from '../auth/authMiddleware.js' const router = express.Router() // ============================================================ // HNS 분석 라우트 (/:id 보다 먼저 등록) // ============================================================ // GET /api/hns/analyses — 분석 목록 router.get('/analyses', requireAuth, requirePermission('hns', 'READ'), async (req, res) => { try { const { status, substance, search } = req.query const items = await listAnalyses({ status: status as string | undefined, substance: substance as string | undefined, search: search as string | undefined, }) res.json(items) } catch (err) { console.error('[hns] 분석 목록 오류:', err) res.status(500).json({ error: 'HNS 분석 목록 조회 실패' }) } }) // GET /api/hns/analyses/:sn — 분석 상세 router.get('/analyses/:sn', requireAuth, requirePermission('hns', 'READ'), async (req, res) => { try { const sn = parseInt(req.params.sn as string, 10) if (!isValidNumber(sn, 1, 999999)) { res.status(400).json({ error: '유효하지 않은 분석 번호' }) return } const item = await getAnalysis(sn) if (!item) { res.status(404).json({ error: '분석을 찾을 수 없습니다' }) return } res.json(item) } catch (err) { console.error('[hns] 분석 상세 오류:', err) res.status(500).json({ error: 'HNS 분석 조회 실패' }) } }) // POST /api/hns/analyses — 분석 생성 router.post('/analyses', requireAuth, requirePermission('hns', 'CREATE'), async (req, res) => { try { const { anlysNm, acdntDtm, locNm, lon, lat, sbstNm, spilQty, spilUnitCd, fcstHr, algoCd, critMdlCd, windSpd, windDir, temp, humid, atmStblCd, analystNm } = req.body if (!anlysNm) { res.status(400).json({ error: '분석명은 필수입니다.' }) return } const result = await createAnalysis({ anlysNm, acdntDtm, locNm, lon, lat, sbstNm, spilQty, spilUnitCd, fcstHr, algoCd, critMdlCd, windSpd, windDir, temp, humid, atmStblCd, analystNm, }) res.status(201).json(result) } catch (err) { console.error('[hns] 분석 생성 오류:', err) res.status(500).json({ error: 'HNS 분석 생성 실패' }) } }) // POST /api/hns/analyses/:sn/save — 분석 결과 저장 (PUT 금지 정책 준수) router.post('/analyses/:sn/save', requireAuth, requirePermission('hns', 'CREATE'), async (req, res) => { try { const sn = parseInt(req.params.sn as string, 10) if (!isValidNumber(sn, 1, 999999)) { res.status(400).json({ error: '유효하지 않은 분석 번호' }) return } const { rsltData, execSttsCd, riskCd } = req.body if (!rsltData) { res.status(400).json({ error: '결과 데이터는 필수입니다.' }) return } await updateAnalysisResult(sn, { rsltData, execSttsCd, riskCd }) res.json({ success: true }) } catch (err) { console.error('[hns] 분석 결과 저장 오류:', err) res.status(500).json({ error: 'HNS 분석 결과 저장 실패' }) } }) // DELETE /api/hns/analyses/:sn — 분석 삭제 router.delete('/analyses/:sn', requireAuth, requirePermission('hns', 'DELETE'), async (req, res) => { try { const sn = parseInt(req.params.sn as string, 10) if (!isValidNumber(sn, 1, 999999)) { res.status(400).json({ error: '유효하지 않은 분석 번호' }) return } await deleteAnalysis(sn) res.json({ success: true }) } catch (err) { console.error('[hns] 분석 삭제 오류:', err) res.status(500).json({ error: 'HNS 분석 삭제 실패' }) } }) // ============================================================ // HNS 물질 라우트 // ============================================================ // HNS 물질 검색 router.get('/', async (req, res) => { try { const q = req.query.q as string | undefined const type = req.query.type as string | undefined const sebc = req.query.sebc as string | undefined const page = parseInt(req.query.page as string, 10) || 1 const limit = parseInt(req.query.limit as string, 10) || 50 if (!isValidNumber(page, 1, 10000) || !isValidNumber(limit, 1, 100)) { return res.status(400).json({ error: '유효하지 않은 페이지네이션', message: 'page는 1~10000, limit은 1~100 범위여야 합니다.', }) } const validTypes = ['abbreviation', 'nameKr', 'nameEn', 'casNumber', 'unNumber', 'cargoCode'] const searchType = type && validTypes.includes(type) ? type as 'abbreviation' | 'nameKr' | 'nameEn' | 'casNumber' | 'unNumber' | 'cargoCode' : undefined const result = await searchSubstances({ q, type: searchType, sebc, page, limit }) res.json(result) } catch { res.status(500).json({ error: 'HNS 물질 검색 실패' }) } }) // HNS 물질 상세 조회 router.get('/:id', async (req, res) => { try { const id = parseInt(req.params.id, 10) if (!isValidNumber(id, 1, 999999)) { return res.status(400).json({ error: '유효하지 않은 물질 ID' }) } const substance = await getSubstanceById(id) if (!substance) { return res.status(404).json({ error: '물질을 찾을 수 없습니다' }) } res.json(substance) } catch { res.status(500).json({ error: 'HNS 물질 조회 실패' }) } }) export default router