Tạo scripts backup dữ liệu
This commit is contained in:
@@ -4,6 +4,7 @@ const path = require('path');
|
||||
const fs = require('fs');
|
||||
const crypto = require('crypto');
|
||||
const sharp = require('sharp');
|
||||
const AdmZip = require('adm-zip');
|
||||
|
||||
const User = require('../models/User');
|
||||
const Asset = require('../models/Asset');
|
||||
@@ -53,6 +54,83 @@ const upload = multer({
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @route POST /api/admin/backup
|
||||
* @desc Tạo bản sao lưu toàn bộ hệ thống (DB + Uploads)
|
||||
* @access Private (Admin)
|
||||
*/
|
||||
router.post('/admin/backup', protect, async (req, res) => {
|
||||
if (req.user.role !== 'admin' && req.user.role !== 'Chủ sở hữu') {
|
||||
return res.status(403).json({ message: 'Forbidden' });
|
||||
}
|
||||
try {
|
||||
const zip = new AdmZip();
|
||||
// 1. Export Database
|
||||
const dbData = {
|
||||
users: await User.find().lean(),
|
||||
assets: await Asset.find().lean(),
|
||||
scenes: await Scene.find().lean(),
|
||||
hotspots: await Hotspot.find().lean(),
|
||||
settings: await Setting.find().lean()
|
||||
};
|
||||
zip.addFile("database.json", Buffer.from(JSON.stringify(dbData, null, 2), "utf8"));
|
||||
|
||||
// 2. Add Uploads folder
|
||||
if (fs.existsSync(uploadDir)) {
|
||||
zip.addLocalFolder(uploadDir, "uploads");
|
||||
}
|
||||
|
||||
const buffer = zip.toBuffer();
|
||||
res.set({
|
||||
'Content-Type': 'application/zip',
|
||||
'Content-Disposition': 'attachment; filename="backup_3dtour.zip"'
|
||||
});
|
||||
res.send(buffer);
|
||||
} catch (error) {
|
||||
res.status(500).json({ message: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @route POST /api/admin/restore
|
||||
* @desc Khôi phục hệ thống từ file backup.zip
|
||||
* @access Private (Admin)
|
||||
*/
|
||||
router.post('/admin/restore', protect, upload.single('backupFile'), async (req, res) => {
|
||||
if (req.user.role !== 'admin' && req.user.role !== 'Chủ sở hữu') {
|
||||
if (req.file) fs.unlinkSync(req.file.path);
|
||||
return res.status(403).json({ message: 'Forbidden' });
|
||||
}
|
||||
if (!req.file) return res.status(400).json({ message: 'Vui lòng upload file backup.zip' });
|
||||
|
||||
try {
|
||||
const zip = new AdmZip(req.file.path);
|
||||
const dbEntry = zip.getEntry("database.json");
|
||||
if (!dbEntry) throw new Error("File backup không hợp lệ (thiếu database.json)");
|
||||
|
||||
const dbData = JSON.parse(dbEntry.getData().toString('utf8'));
|
||||
|
||||
// Khôi phục Database (Xóa cũ - Ghi mới)
|
||||
await Promise.all([
|
||||
User.deleteMany({}), Asset.deleteMany({}), Scene.deleteMany({}),
|
||||
Hotspot.deleteMany({}), Setting.deleteMany({})
|
||||
]);
|
||||
await Promise.all([
|
||||
User.insertMany(dbData.users), Asset.insertMany(dbData.assets),
|
||||
Scene.insertMany(dbData.scenes), Hotspot.insertMany(dbData.hotspots),
|
||||
Setting.insertMany(dbData.settings)
|
||||
]);
|
||||
|
||||
// Khôi phục Files
|
||||
zip.extractEntryTo("uploads/", uploadDir, false, true);
|
||||
fs.unlinkSync(req.file.path);
|
||||
res.json({ message: 'Khôi phục dữ liệu thành công' });
|
||||
} catch (error) {
|
||||
if (req.file && fs.existsSync(req.file.path)) fs.unlinkSync(req.file.path);
|
||||
res.status(500).json({ message: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Wrapper for Multer middleware to catch "Request aborted" and other upload errors gracefully.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user