fix: rekursive Ordner-Löschung, Multer-Cleanup, Waisen-Bereinigung (Disk+DB)
This commit is contained in:
@@ -319,4 +319,69 @@ router.post('/webdav/sync', authenticate, requireAdmin, async (req, res) => {
|
||||
});
|
||||
|
||||
|
||||
// ── Waisen aufräumen ──────────────────────────────────────────────────────
|
||||
// Findet und löscht:
|
||||
// 1. Dateien auf Disk die nicht in der DB sind (Disk-Waisen)
|
||||
// 2. DB-Einträge die keine Datei auf Disk haben (DB-Waisen)
|
||||
router.post('/cleanup-orphans', authenticate, requireAdmin, (req, res) => {
|
||||
const { dry_run = false } = req.body;
|
||||
const UPLOAD_DIR = process.env.UPLOAD_DIR || '/data/uploads';
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
|
||||
const results = {
|
||||
disk_orphans: [], // auf Disk aber nicht in DB
|
||||
db_orphans: [], // in DB aber nicht auf Disk
|
||||
disk_deleted: 0,
|
||||
db_deleted: 0,
|
||||
};
|
||||
|
||||
try {
|
||||
// Alle Dateinamen aus DB
|
||||
const dbFiles = db.prepare('SELECT id, filename, originalname, size FROM files').all();
|
||||
const dbFilenames = new Set(dbFiles.map(f => f.filename));
|
||||
|
||||
// Alle Dateien auf Disk
|
||||
const diskFiles = fs.readdirSync(UPLOAD_DIR).filter(f => !f.startsWith('.'));
|
||||
|
||||
// 1. Disk-Waisen: auf Disk aber nicht in DB
|
||||
for (const diskFile of diskFiles) {
|
||||
if (!dbFilenames.has(diskFile)) {
|
||||
const fullPath = path.join(UPLOAD_DIR, diskFile);
|
||||
const stat = fs.statSync(fullPath);
|
||||
results.disk_orphans.push({ filename: diskFile, size: stat.size });
|
||||
if (!dry_run) {
|
||||
try { fs.unlinkSync(fullPath); results.disk_deleted++; } catch(e) {
|
||||
console.error('[cleanup] disk unlink failed:', diskFile, e.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. DB-Waisen: in DB aber nicht auf Disk
|
||||
const diskFileset = new Set(diskFiles);
|
||||
for (const dbFile of dbFiles) {
|
||||
if (!diskFileset.has(dbFile.filename)) {
|
||||
results.db_orphans.push({ id: dbFile.id, filename: dbFile.filename, originalname: dbFile.originalname });
|
||||
if (!dry_run) {
|
||||
db.prepare('DELETE FROM files WHERE id=?').run(dbFile.id);
|
||||
results.db_deleted++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
res.json({
|
||||
dry_run,
|
||||
disk_orphans_count: results.disk_orphans.length,
|
||||
db_orphans_count: results.db_orphans.length,
|
||||
disk_deleted: results.disk_deleted,
|
||||
db_deleted: results.db_deleted,
|
||||
disk_orphans: results.disk_orphans.slice(0, 50),
|
||||
db_orphans: results.db_orphans.slice(0, 50),
|
||||
});
|
||||
} catch(err) {
|
||||
res.status(500).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
|
||||
Reference in New Issue
Block a user