import { GeneralService } from '../share/generalservice.js'; import { sendError } from '../utils/response.js'; import { verifyToken } from '../utils/token.js'; // ✅ เพิ่ม verifyToken import fs from 'fs'; import path from 'path'; import archiver from 'archiver'; export class projectDownload { constructor() { this.generalService = new GeneralService(); } async onNavigate(req, res) { this.generalService.devhint(1, 'projectDownload.js', 'onNavigate() start'); const prjseq = req.query.prjseq; const docType = req.query.docType; // ✅ 1. แกะ Token เพื่อหา Database Schema (เพราะต้อง Query DB) let token = req.headers.authorization?.split(' ')[1]; let database = 'dbo'; // Default if (token) { const decoded = verifyToken(token); if (decoded && decoded.organization) { database = decoded.organization; } } if (!prjseq) { return res.status(400).json(sendError('กรุณาระบุ prjseq', 'Missing prjseq parameter')); } return await this.onProjectDownload(req, res, prjseq, docType, database); } async onProjectDownload(req, res, prjseq, docType, database) { try { // ✅ 2. Query เช็คค่า prjdoc ใน Database ก่อน (Source of Truth) const sql = `SELECT prjdoc FROM ${database}.prjmst WHERE prjseq = $1`; const result = await this.generalService.executeQueryParam(database, sql, [prjseq]); // ถ้าไม่เจอโครงการเลย if (result.length === 0) { return res.json(sendError('ไม่พบข้อมูลโครงการนี้ในระบบ', 'Project not found in DB', 404)); } const prjdoc = result[0].prjdoc; // ✅ 3. เช็คว่า prjdoc ว่างหรือไม่? (null, undefined, หรือ string ว่าง) if (!prjdoc || prjdoc.trim() === '') { return res.json(sendError('ไม่พบเอกสารแนบในระบบ (prjdoc ว่าง)', 'No documents recorded in database', 404)); } // ✅ 4. แปลงรายชื่อไฟล์จาก DB (Comma Separated) เป็น Array // ตัวอย่าง: "file1.jpg,file2.pdf" -> ["file1.jpg", "file2.pdf"] let dbFiles = prjdoc.split(',').map(f => f.trim()).filter(f => f !== ''); const folderPath = `uploads/projects/${prjseq}`; // เช็คว่ามีโฟลเดอร์จริงไหม if (!fs.existsSync(folderPath)) { return res.json(sendError('ไม่พบไฟล์ใน Server (โฟลเดอร์สูญหาย)', 'Project folder missing on server', 404)); } // ✅ 5. กรองไฟล์: ต้องมีชื่อใน DB **และ** มีไฟล์อยู่จริงบน Disk // (และผ่าน filter docType ถ้ามี) let validFiles = dbFiles.filter(filename => { // Filter docType (ถ้าส่งมา) if (docType && !filename.toLowerCase().endsWith(`.${docType.toLowerCase()}`)) { return false; } // เช็คว่าไฟล์มีอยู่จริงไหม const fullPath = path.join(folderPath, filename); return fs.existsSync(fullPath); }); // ถ้ากรองแล้วไม่เหลือไฟล์เลย if (validFiles.length === 0) { return res.json(sendError('ไม่พบไฟล์เอกสารที่สามารถดาวน์โหลดได้', 'No valid files found', 404)); } // --- เริ่มกระบวนการ Zip --- const archive = archiver('zip', { zlib: { level: 9 } }); const zipFilename = `project_${prjseq}_documents.zip`; res.attachment(zipFilename); archive.on('error', function(err) { console.error('Archiver Error:', err); if (!res.headersSent) { res.status(500).send({error: err.message}); } }); archive.pipe(res); validFiles.forEach(filename => { const filePath = path.join(folderPath, filename); archive.file(filePath, { name: filename }); }); await archive.finalize(); } catch (error) { console.error('Download Controller Error:', error); if (!res.headersSent) { return res.json(sendError('เกิดข้อผิดพลาดในการดาวน์โหลด', 'Download Error', 500)); } } } }