2025-11-30 19:47:06 +07:00
|
|
|
import { GeneralService } from '../share/generalservice.js';
|
|
|
|
|
import { sendError } from '../utils/response.js';
|
2025-11-30 23:47:47 +07:00
|
|
|
import { verifyToken } from '../utils/token.js'; // ✅ เพิ่ม verifyToken
|
2025-11-30 19:47:06 +07:00
|
|
|
import fs from 'fs';
|
|
|
|
|
import path from 'path';
|
2025-11-30 23:47:47 +07:00
|
|
|
import archiver from 'archiver';
|
2025-11-30 19:47:06 +07:00
|
|
|
|
|
|
|
|
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;
|
2025-11-30 23:47:47 +07:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-11-30 19:47:06 +07:00
|
|
|
|
|
|
|
|
if (!prjseq) {
|
|
|
|
|
return res.status(400).json(sendError('กรุณาระบุ prjseq', 'Missing prjseq parameter'));
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-30 23:47:47 +07:00
|
|
|
return await this.onProjectDownload(req, res, prjseq, docType, database);
|
2025-11-30 19:47:06 +07:00
|
|
|
}
|
|
|
|
|
|
2025-11-30 23:47:47 +07:00
|
|
|
async onProjectDownload(req, res, prjseq, docType, database) {
|
2025-11-30 19:47:06 +07:00
|
|
|
try {
|
2025-11-30 23:47:47 +07:00
|
|
|
// ✅ 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 !== '');
|
|
|
|
|
|
2025-11-30 19:47:06 +07:00
|
|
|
const folderPath = `uploads/projects/${prjseq}`;
|
|
|
|
|
|
2025-11-30 23:47:47 +07:00
|
|
|
// เช็คว่ามีโฟลเดอร์จริงไหม
|
2025-11-30 19:47:06 +07:00
|
|
|
if (!fs.existsSync(folderPath)) {
|
2025-11-30 23:47:47 +07:00
|
|
|
return res.json(sendError('ไม่พบไฟล์ใน Server (โฟลเดอร์สูญหาย)', 'Project folder missing on server', 404));
|
2025-11-30 19:47:06 +07:00
|
|
|
}
|
|
|
|
|
|
2025-11-30 23:47:47 +07:00
|
|
|
// ✅ 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);
|
2025-11-30 19:47:06 +07:00
|
|
|
});
|
|
|
|
|
|
2025-11-30 23:47:47 +07:00
|
|
|
// ถ้ากรองแล้วไม่เหลือไฟล์เลย
|
|
|
|
|
if (validFiles.length === 0) {
|
|
|
|
|
return res.json(sendError('ไม่พบไฟล์เอกสารที่สามารถดาวน์โหลดได้', 'No valid files found', 404));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// --- เริ่มกระบวนการ Zip ---
|
|
|
|
|
const archive = archiver('zip', { zlib: { level: 9 } });
|
2025-11-30 19:47:06 +07:00
|
|
|
const zipFilename = `project_${prjseq}_documents.zip`;
|
|
|
|
|
|
2025-11-30 23:47:47 +07:00
|
|
|
res.attachment(zipFilename);
|
2025-11-30 19:47:06 +07:00
|
|
|
|
|
|
|
|
archive.on('error', function(err) {
|
2025-11-30 23:47:47 +07:00
|
|
|
console.error('Archiver Error:', err);
|
|
|
|
|
if (!res.headersSent) {
|
|
|
|
|
res.status(500).send({error: err.message});
|
|
|
|
|
}
|
2025-11-30 19:47:06 +07:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
archive.pipe(res);
|
|
|
|
|
|
2025-11-30 23:47:47 +07:00
|
|
|
validFiles.forEach(filename => {
|
|
|
|
|
const filePath = path.join(folderPath, filename);
|
|
|
|
|
archive.file(filePath, { name: filename });
|
|
|
|
|
});
|
2025-11-30 19:47:06 +07:00
|
|
|
|
|
|
|
|
await archive.finalize();
|
|
|
|
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('Download Controller Error:', error);
|
2025-11-30 23:47:47 +07:00
|
|
|
if (!res.headersSent) {
|
|
|
|
|
return res.json(sendError('เกิดข้อผิดพลาดในการดาวน์โหลด', 'Download Error', 500));
|
|
|
|
|
}
|
2025-11-30 19:47:06 +07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|