import { Router } from 'express'; import { requireAuth, requirePermission } from '../auth/authMiddleware.js'; import { AuthError } from '../auth/authService.js'; import { getTemplates, getCategories, listReports, getReport, createReport, updateReport, deleteReport, updateReportSection, } from './reportsService.js'; const router = Router(); // ============================================================ // GET /api/reports/templates — 템플릿 목록 + 섹션 정의 // ============================================================ router.get('/templates', requireAuth, async (_req, res) => { try { const templates = await getTemplates(); res.json(templates); } catch (err) { console.error('[reports] 템플릿 조회 오류:', err); res.status(500).json({ error: '템플릿 조회 중 오류가 발생했습니다.' }); } }); // ============================================================ // GET /api/reports/categories — 분석 카테고리 목록 + 섹션 정의 // ============================================================ router.get('/categories', requireAuth, async (_req, res) => { try { const categories = await getCategories(); res.json(categories); } catch (err) { console.error('[reports] 카테고리 조회 오류:', err); res.status(500).json({ error: '카테고리 조회 중 오류가 발생했습니다.' }); } }); // ============================================================ // GET /api/reports — 보고서 목록 // ============================================================ router.get('/', requireAuth, requirePermission('reports', 'READ'), async (req, res) => { try { const { jrsdCd, tmplCd, sttsCd, search, page, size } = req.query; const result = await listReports({ jrsdCd: jrsdCd as string | undefined, tmplCd: tmplCd as string | undefined, sttsCd: sttsCd as string | undefined, search: search as string | undefined, page: page ? parseInt(page as string, 10) : undefined, size: size ? parseInt(size as string, 10) : undefined, }); res.json(result); } catch (err) { console.error('[reports] 목록 조회 오류:', err); if (err instanceof AuthError) { res.status(err.status).json({ error: err.message }); } else { res.status(500).json({ error: '보고서 목록 조회 중 오류가 발생했습니다.' }); } } }); // ============================================================ // GET /api/reports/:sn — 보고서 상세 // ============================================================ router.get('/:sn', requireAuth, requirePermission('reports', 'READ'), async (req, res) => { try { const sn = parseInt(req.params.sn as string, 10); if (isNaN(sn)) { res.status(400).json({ error: '유효하지 않은 보고서 번호입니다.' }); return; } const report = await getReport(sn); res.json(report); } catch (err) { if (err instanceof AuthError) { res.status(err.status).json({ error: err.message }); } else { console.error('[reports] 상세 조회 오류:', err); res.status(500).json({ error: '보고서 조회 중 오류가 발생했습니다.' }); } } }); // ============================================================ // POST /api/reports — 보고서 생성 // ============================================================ router.post('/', requireAuth, requirePermission('reports', 'CREATE'), async (req, res) => { try { const { tmplSn, ctgrSn, acdntSn, title, jrsdCd, sttsCd, sections, step3MapImg, step6MapImg } = req.body; const result = await createReport({ tmplSn, ctgrSn, acdntSn, title, jrsdCd, sttsCd, authorId: req.user!.sub, step3MapImg, step6MapImg, sections, }); res.status(201).json(result); } catch (err) { if (err instanceof AuthError) { res.status(err.status).json({ error: err.message }); } else { console.error('[reports] 생성 오류:', err); res.status(500).json({ error: '보고서 생성 중 오류가 발생했습니다.' }); } } }); // ============================================================ // POST /api/reports/:sn/update — 보고서 수정 // ============================================================ router.post('/:sn/update', requireAuth, requirePermission('reports', 'UPDATE'), async (req, res) => { try { const sn = parseInt(req.params.sn as string, 10); if (isNaN(sn)) { res.status(400).json({ error: '유효하지 않은 보고서 번호입니다.' }); return; } const { title, jrsdCd, sttsCd, acdntSn, sections, step3MapImg, step6MapImg } = req.body; await updateReport(sn, { title, jrsdCd, sttsCd, acdntSn, sections, step3MapImg, step6MapImg }, req.user!.sub); res.json({ success: true }); } catch (err) { if (err instanceof AuthError) { res.status(err.status).json({ error: err.message }); } else { console.error('[reports] 수정 오류:', err); res.status(500).json({ error: '보고서 수정 중 오류가 발생했습니다.' }); } } }); // ============================================================ // POST /api/reports/:sn/delete — 보고서 삭제 (논리 삭제) // ============================================================ router.post('/:sn/delete', requireAuth, requirePermission('reports', 'DELETE'), async (req, res) => { try { const sn = parseInt(req.params.sn as string, 10); if (isNaN(sn)) { res.status(400).json({ error: '유효하지 않은 보고서 번호입니다.' }); return; } await deleteReport(sn, req.user!.sub); res.json({ success: true }); } catch (err) { if (err instanceof AuthError) { res.status(err.status).json({ error: err.message }); } else { console.error('[reports] 삭제 오류:', err); res.status(500).json({ error: '보고서 삭제 중 오류가 발생했습니다.' }); } } }); // ============================================================ // POST /api/reports/:sn/sections/:sectCd — 개별 섹션 수정 // ============================================================ router.post('/:sn/sections/:sectCd', requireAuth, requirePermission('reports', 'UPDATE'), async (req, res) => { try { const sn = parseInt(req.params.sn as string, 10); if (isNaN(sn)) { res.status(400).json({ error: '유효하지 않은 보고서 번호입니다.' }); return; } const { sectData, includeYn } = req.body; await updateReportSection(sn, req.params.sectCd as string, sectData, includeYn, req.user!.sub); res.json({ success: true }); } catch (err) { if (err instanceof AuthError) { res.status(err.status).json({ error: err.message }); } else { console.error('[reports] 섹션 수정 오류:', err); res.status(500).json({ error: '섹션 수정 중 오류가 발생했습니다.' }); } } }); export default router;