feat: Sync legt alle Ordner an (inkl. leere), Upload-Freigaben in _Upload-Freigaben/

This commit is contained in:
2026-06-14 02:06:04 +02:00
parent e2d28e285c
commit 3d76ae9ce5
2 changed files with 67 additions and 6 deletions

View File

@@ -247,21 +247,53 @@ router.post('/webdav/sync', authenticate, requireAdmin, async (req, res) => {
visited.add(current);
const folder = db.prepare('SELECT id, name, parent_id FROM folders WHERE id=?').get(current);
if (!folder) break;
parts.unshift(folder.name.replace(/[/\\]/g, '_'));
parts.unshift(folder.name.replace(/[\/\\]/g, '_'));
current = folder.parent_id;
}
return parts.join('/');
}
// Alle Dateien aus DB holen mit Username und folder_id
const results = { folders: 0, ok: 0, failed: 0, errors: [] };
// ── Schritt 1: Alle User-Basisordner + Unterordner anlegen ───────────────
const users = db.prepare('SELECT id, username FROM users ORDER BY id').all();
for (const user of users) {
const userBase = webdav.userPath(cfg, user.username);
// User-Basisordner
try { await webdav.mkdirp(userBase); results.folders++; } catch(e) {
results.errors.push(`Ordner ${userBase}: ${e.message}`);
}
// Upload-Freigabe Ordner
try { await webdav.mkdirp(`${userBase}/_Upload-Freigaben`); results.folders++; } catch {}
// Alle DB-Ordner dieses Users (sortiert nach parent_id damit Parents zuerst)
const folders = db.prepare(`
WITH RECURSIVE tree AS (
SELECT id, name, parent_id, 0 as depth FROM folders WHERE user_id=? AND parent_id IS NULL
UNION ALL
SELECT f.id, f.name, f.parent_id, t.depth+1 FROM folders f JOIN tree t ON f.parent_id=t.id
) SELECT * FROM tree ORDER BY depth, id
`).all(user.id);
for (const folder of folders) {
const folderPath = getFolderPath(folder.id);
const davPath = `${userBase}/${folderPath}`;
try { await webdav.mkdirp(davPath); results.folders++; } catch(e) {
results.errors.push(`Ordner ${davPath}: ${e.message}`);
}
}
}
// ── Schritt 2: Alle Dateien hochladen ────────────────────────────────────
const files = db.prepare(`
SELECT f.*, u.username FROM files f
JOIN users u ON u.id = f.user_id
ORDER BY f.user_id, f.folder_id, f.id
`).all();
const results = { ok: 0, failed: 0, errors: [] };
for (const file of files) {
const localPath = path.join(UPLOAD_DIR, file.filename);
if (!fs.existsSync(localPath)) {
@@ -284,7 +316,36 @@ router.post('/webdav/sync', authenticate, requireAdmin, async (req, res) => {
}
}
res.json({ total: files.length, ...results });
// ── Schritt 3: Upload-Freigabe Dateien ───────────────────────────────────
const uploadLogs = db.prepare(`
SELECT l.filename, l.originalname, l.mimetype, l.size,
s.user_id, u.username
FROM upload_share_logs l
JOIN upload_shares s ON s.id = l.share_id
JOIN users u ON u.id = s.user_id
WHERE l.filename IS NOT NULL
`).all();
for (const log of uploadLogs) {
const localPath = path.join(UPLOAD_DIR, log.filename);
if (!fs.existsSync(localPath)) continue;
try {
const buf = fs.readFileSync(localPath);
const userBase = webdav.userPath(cfg, log.username);
const davPath = `${userBase}/_Upload-Freigaben/${log.originalname || log.filename}`;
await webdav.uploadFile(buf, davPath, log.mimetype || 'application/octet-stream');
results.ok++;
} catch(e) {
results.failed++;
results.errors.push(`Upload-Freigabe ${log.originalname}: ${e.message}`);
}
}
res.json({
total: files.length + uploadLogs.length,
...results,
message: `${results.folders} Ordner angelegt, ${results.ok} Dateien kopiert, ${results.failed} fehlgeschlagen`
});
});
module.exports = router;

View File

@@ -2818,7 +2818,7 @@ function WebDavSettings({ toast }) {
{syncResult && !syncResult.error && (
<div style={{padding:'10px 12px',background:'rgba(74,222,128,0.08)',border:'1px solid rgba(74,222,128,0.3)',borderRadius:8,fontFamily:'monospace',fontSize:11}}>
<div style={{color:'#4ade80',marginBottom:4}}>
Sync abgeschlossen: {syncResult.ok}/{syncResult.total} erfolgreich
{syncResult.message || `Sync abgeschlossen: ${syncResult.ok}/${syncResult.total} Dateien`}
</div>
{syncResult.failed > 0 && (
<div style={{color:'#f87171'}}>