127 lines
4.3 KiB
JavaScript
127 lines
4.3 KiB
JavaScript
const express = require('express');
|
|
const router = express.Router();
|
|
const path = require('path');
|
|
const fs = require('fs');
|
|
const multer = require('multer');
|
|
const { getDb, logAudit } = require('../db');
|
|
const {
|
|
collectStats,
|
|
formatBytes,
|
|
createBackup,
|
|
listBackups,
|
|
getBackupPath,
|
|
deleteBackup,
|
|
restoreBackup,
|
|
getPaths
|
|
} = require('../lib/backup');
|
|
|
|
function requireAdmin(req, res, next) {
|
|
const db = getDb();
|
|
const user = db.prepare('SELECT * FROM users WHERE id = ?').get(req.session.userId);
|
|
if (!user || user.role !== 'admin') return res.status(403).render('404', { path: req.path });
|
|
next();
|
|
}
|
|
|
|
const uploadDir = path.join(getPaths().dataDir, 'backups', 'uploads-tmp');
|
|
if (!fs.existsSync(uploadDir)) fs.mkdirSync(uploadDir, { recursive: true });
|
|
|
|
const upload = multer({
|
|
dest: uploadDir,
|
|
limits: { fileSize: 500 * 1024 * 1024 },
|
|
fileFilter: (req, file, cb) => {
|
|
if (file.originalname.endsWith('.tar.gz') || file.originalname.endsWith('.tgz') || file.mimetype === 'application/gzip') {
|
|
cb(null, true);
|
|
} else {
|
|
cb(new Error('Alleen .tar.gz backupbestanden'));
|
|
}
|
|
}
|
|
});
|
|
|
|
router.get('/', requireAdmin, (req, res) => {
|
|
const stats = collectStats();
|
|
const backups = listBackups();
|
|
const disk = getPaths();
|
|
let diskFree = null;
|
|
try {
|
|
const { execSync } = require('child_process');
|
|
const out = execSync(`df -B1 "${disk.dataDir}" 2>/dev/null | tail -1`, { encoding: 'utf8' });
|
|
const parts = out.trim().split(/\s+/);
|
|
if (parts.length >= 4) diskFree = formatBytes(parseInt(parts[3], 10));
|
|
} catch (e) { /* ignore */ }
|
|
|
|
res.render('backup', {
|
|
stats,
|
|
backups,
|
|
diskFree,
|
|
formatBytes,
|
|
restored: req.query.restored === '1',
|
|
created: req.query.created === '1',
|
|
deleted: req.query.deleted === '1',
|
|
error: req.query.error || null,
|
|
user: { username: req.session.username }
|
|
});
|
|
});
|
|
|
|
router.post('/create', requireAdmin, (req, res) => {
|
|
try {
|
|
const backup = createBackup();
|
|
logAudit(req.session.userId, req.session.username, 'backup_create', 'system', 0, backup.filename);
|
|
if (req.query.download === '1') {
|
|
return res.download(backup.path, backup.filename);
|
|
}
|
|
res.redirect('/backup?created=1');
|
|
} catch (e) {
|
|
console.error('Backup create error:', e);
|
|
res.redirect('/backup?error=' + encodeURIComponent('Backup mislukt: ' + e.message));
|
|
}
|
|
});
|
|
|
|
router.get('/download/:filename', requireAdmin, (req, res) => {
|
|
const p = getBackupPath(req.params.filename);
|
|
if (!p) return res.redirect('/backup?error=' + encodeURIComponent('Backup niet gevonden'));
|
|
logAudit(req.session.userId, req.session.username, 'backup_download', 'system', 0, req.params.filename);
|
|
res.download(p, req.params.filename);
|
|
});
|
|
|
|
router.post('/delete/:filename', requireAdmin, (req, res) => {
|
|
try {
|
|
if (!deleteBackup(req.params.filename)) {
|
|
return res.redirect('/backup?error=' + encodeURIComponent('Backup niet gevonden'));
|
|
}
|
|
logAudit(req.session.userId, req.session.username, 'backup_delete', 'system', 0, req.params.filename);
|
|
res.redirect('/backup?deleted=1');
|
|
} catch (e) {
|
|
res.redirect('/backup?error=' + encodeURIComponent(e.message));
|
|
}
|
|
});
|
|
|
|
router.post('/restore', requireAdmin, upload.single('backup_file'), (req, res) => {
|
|
if (!req.file) {
|
|
return res.redirect('/backup?error=' + encodeURIComponent('Geen bestand geüpload'));
|
|
}
|
|
try {
|
|
const result = restoreBackup(req.file.path);
|
|
fs.unlinkSync(req.file.path);
|
|
logAudit(req.session.userId, req.session.username, 'backup_restore', 'system', 0, JSON.stringify(result));
|
|
res.redirect('/backup?restored=1');
|
|
} catch (e) {
|
|
console.error('Restore error:', e);
|
|
try { fs.unlinkSync(req.file.path); } catch (err) { /* ignore */ }
|
|
res.redirect('/backup?error=' + encodeURIComponent('Herstel mislukt: ' + e.message));
|
|
}
|
|
});
|
|
|
|
router.post('/restore/:filename', requireAdmin, (req, res) => {
|
|
const p = getBackupPath(req.params.filename);
|
|
if (!p) return res.redirect('/backup?error=' + encodeURIComponent('Backup niet gevonden'));
|
|
try {
|
|
const result = restoreBackup(p);
|
|
logAudit(req.session.userId, req.session.username, 'backup_restore', 'system', 0, req.params.filename);
|
|
res.redirect('/backup?restored=1');
|
|
} catch (e) {
|
|
res.redirect('/backup?error=' + encodeURIComponent('Herstel mislukt: ' + e.message));
|
|
}
|
|
});
|
|
|
|
module.exports = router;
|