const mongoose = require('mongoose'); const fs = require('fs'); const path = require('path'); const connectDB = require('../config/db'); const Asset = require('../models/Asset'); const Scene = require('../models/Scene'); /** * Script kiểm tra tính toàn vẹn dữ liệu * So sánh sự đồng bộ giữa Database (MongoDB) và Filesystem (thư mục uploads) */ const checkIntegrity = async () => { try { console.log('=== KHỞI CHẠY KIỂM TRA TÍNH TOÀN VẸN HỆ THỐNG ==='); await connectDB(); const assets = await Asset.find().lean(); const scenes = await Scene.find().lean(); const uploadDir = path.resolve(__dirname, '../uploads'); const tempDir = path.resolve(uploadDir, 'temp'); const dbFilePaths = new Set(); const brokenAssets = []; const assetIdsInDB = new Set(assets.map(a => a._id.toString())); console.log(`\n1. Kiểm tra Database -> Filesystem (${assets.length} Assets):`); for (const asset of assets) { if (asset.filePath) { const absolutePath = path.resolve(asset.filePath); dbFilePaths.add(absolutePath); if (!fs.existsSync(absolutePath)) { brokenAssets.push({ id: asset._id, path: asset.filePath, user: asset.uploadedBy }); } } } if (brokenAssets.length > 0) { console.error(` [!] CẢNH BÁO: Tìm thấy ${brokenAssets.length} bản ghi mất file vật lý:`); brokenAssets.forEach(ba => console.error(` - Asset ID: ${ba.id} | Path: ${ba.path}`)); } else { console.log(' [✓] Tất cả bản ghi Asset đều có file vật lý tương ứng.'); } console.log(`\n2. Kiểm tra Filesystem -> Database:`); let strayFilesCount = 0; if (fs.existsSync(uploadDir)) { const files = fs.readdirSync(uploadDir); files.forEach(file => { const fullPath = path.join(uploadDir, file); // Bỏ qua thư mục temp và các thư mục con khác if (fs.lstatSync(fullPath).isFile() && !file.startsWith('.')) { if (!dbFilePaths.has(path.resolve(fullPath))) { console.warn(` [?] File không có bản ghi DB: ${file}`); strayFilesCount++; } } }); } console.log(` [i] Tìm thấy ${strayFilesCount} file mồ côi (không được quản lý bởi Asset).`); console.log(`\n3. Kiểm tra Liên kết Scene -> Asset (${scenes.length} Scenes):`); let brokenScenesCount = 0; for (const scene of scenes) { const assetId = scene.assetId?.toString(); if (assetId && !assetIdsInDB.has(assetId)) { console.error(` [!] Scene "${scene.name || scene.title}" (ID: ${scene._id}) trỏ tới Asset ID không tồn tại: ${assetId}`); brokenScenesCount++; } } if (brokenScenesCount === 0) { console.log(' [✓] Tất cả các Scene đều liên kết với Asset hợp lệ.'); } else { console.error(` [!] Tìm thấy ${brokenScenesCount} Scene bị hỏng liên kết.`); } console.log('\n=== TỔNG KẾT ==='); console.log(`- Bản ghi Asset lỗi: ${brokenAssets.length}`); console.log(`- File mồ côi: ${strayFilesCount}`); console.log(`- Scene hỏng liên kết: ${brokenScenesCount}`); console.log('================================================'); mongoose.connection.close(); process.exit(0); } catch (err) { console.error('Lỗi nghiêm trọng khi kiểm tra:', err.message); if (mongoose.connection) mongoose.connection.close(); process.exit(1); } }; checkIntegrity();