feat: WebDAV Echtzeit-Sync bei Datei/Ordner erstellen und löschen

This commit is contained in:
2026-06-14 02:25:11 +02:00
parent c3b8ff96de
commit 28eef2a39f

View File

@@ -10,6 +10,42 @@ const UPLOAD_DIR = process.env.UPLOAD_DIR || '/data/uploads';
if (!fs.existsSync(UPLOAD_DIR)) fs.mkdirSync(UPLOAD_DIR, { recursive: true });
const webdav = require('./webdav');
// ── WebDAV Hilfsfunktionen ────────────────────────────────────────────────
function getFolderPathById(folderId) {
if (!folderId) return '';
const parts = [];
let cur = folderId;
const seen = new Set();
while (cur) {
if (seen.has(cur)) break; seen.add(cur);
const fo = db.prepare('SELECT name, parent_id FROM folders WHERE id=?').get(cur);
if (!fo) break;
parts.unshift(fo.name.replace(/[\/]/g, '_'));
cur = fo.parent_id;
}
return parts.join('/');
}
function davFileUrl(username, folderId, filename) {
const cfg = webdav.getConfig();
if (!cfg.enabled) return null;
const base = webdav.userPath(cfg, username);
const folder = getFolderPathById(folderId);
return folder ? `${base}/${folder}/${filename}` : `${base}/${filename}`;
}
function davFolderUrl(username, folderId) {
const cfg = webdav.getConfig();
if (!cfg.enabled) return null;
const base = webdav.userPath(cfg, username);
const folder = getFolderPathById(folderId);
return folder ? `${base}/${folder}` : base;
}
function getUserName(userId) {
return db.prepare('SELECT username FROM users WHERE id=?').get(userId)?.username || String(userId);
}
const getSetting = key => db.prepare('SELECT value FROM admin_settings WHERE key=?').get(key)?.value;
const diskStorage = multer.diskStorage({
@@ -102,7 +138,11 @@ router.post('/folders', authenticate, (req, res) => {
if (!parent) return res.status(404).json({ error: 'Überordner nicht gefunden' });
}
const r = db.prepare('INSERT INTO folders (user_id,name,parent_id) VALUES (?,?,?)').run(req.user.id, name.trim(), parentId);
res.json(enrichFolder(db.prepare('SELECT * FROM folders WHERE id=?').get(r.lastInsertRowid)));
const newFolder = db.prepare('SELECT * FROM folders WHERE id=?').get(r.lastInsertRowid);
// WebDAV: Ordner anlegen
const _davFolderCreate = davFolderUrl(getUserName(req.user.id), newFolder.id);
if (_davFolderCreate) webdav.mkdirp(_davFolderCreate).catch(e => console.warn('[webdav] mkdir:', e.message));
res.json(enrichFolder(newFolder));
});
router.delete('/folders/:id', authenticate, (req, res) => {
@@ -111,6 +151,9 @@ router.delete('/folders/:id', authenticate, (req, res) => {
// Delete all files inside
const files = db.prepare('SELECT * FROM files WHERE folder_id=? AND user_id=?').all(folder.id, req.user.id);
for (const f of files) { try { fs.unlinkSync(path.join(UPLOAD_DIR, f.filename)); } catch {} }
// WebDAV: Ordner löschen (vor DB-Löschung damit Pfad noch auflösbar)
const _davFolderDel = davFolderUrl(getUserName(req.user.id), folder.id);
if (_davFolderDel) webdav.deleteFile(_davFolderDel).catch(e => console.warn('[webdav] rmdir:', e.message));
db.prepare('DELETE FROM files WHERE folder_id=? AND user_id=?').run(folder.id, req.user.id);
db.prepare('DELETE FROM folders WHERE id=?').run(folder.id);
res.json({ success: true });
@@ -200,32 +243,11 @@ router.post('/', authenticate, (req, res) => {
.run(uid, req.file.filename, req.file.originalname, req.file.mimetype||'application/octet-stream', req.file.size, folderId);
const newFile = db.prepare('SELECT f.*,u.username as owner FROM files f JOIN users u ON u.id=f.user_id WHERE f.id=?').get(r.lastInsertRowid);
// WebDAV: Datei asynchron spiegeln mit Ordnerstruktur
const cfg = webdav.getConfig();
if (cfg.enabled) {
const user = db.prepare('SELECT username FROM users WHERE id=?').get(uid);
// Ordnerpfad auflösen
function getFolderPath(fid) {
if (!fid) return '';
const parts = [];
let cur = fid;
const seen = new Set();
while (cur) {
if (seen.has(cur)) break; seen.add(cur);
const fo = db.prepare('SELECT name, parent_id FROM folders WHERE id=?').get(cur);
if (!fo) break;
parts.unshift(fo.name.replace(/[/\\]/g, '_'));
cur = fo.parent_id;
}
return parts.join('/');
}
const folderPath = getFolderPath(folderId);
const userBase = webdav.userPath(cfg, user.username);
const davPath = folderPath
? `${userBase}/${folderPath}/${req.file.originalname}`
: `${userBase}/${req.file.originalname}`;
// WebDAV: Datei asynchron spiegeln
const _davPath = davFileUrl(getUserName(uid), folderId, req.file.originalname);
if (_davPath) {
fs.readFile(path.join(UPLOAD_DIR, req.file.filename), (err, buf) => {
if (!err) webdav.uploadFile(buf, davPath, req.file.mimetype).catch(e => console.error('[webdav upload]', e.message));
if (!err) webdav.uploadFile(buf, _davPath, req.file.mimetype).catch(e => console.error('[webdav upload]', e.message));
});
}
@@ -333,6 +355,9 @@ router.get('/:id/download', authenticate, async (req, res) => {
router.delete('/:id', authenticate, (req, res) => {
const file = db.prepare('SELECT * FROM files WHERE id=? AND user_id=?').get(req.params.id, req.user.id);
if (!file) return res.status(404).json({ error: 'Nicht gefunden' });
// WebDAV: Datei löschen
const _davFileDel = davFileUrl(getUserName(file.user_id), file.folder_id, file.originalname);
if (_davFileDel) webdav.deleteFile(_davFileDel).catch(e => console.warn('[webdav] delete:', e.message));
try { fs.unlinkSync(path.join(UPLOAD_DIR, file.filename)); } catch {}
db.prepare('DELETE FROM files WHERE id=?').run(file.id);
res.json({ success: true });