From 61ce2ec2444bbeeb96a27ac5549c632416d1f222 Mon Sep 17 00:00:00 2001 From: Stefan Hacker Date: Sat, 11 Apr 2026 18:17:39 +0200 Subject: [PATCH] feat: Drag & Drop Upload mit Ordner-Unterstuetzung Dateien und komplette Verzeichnisse koennen jetzt hochgeladen werden: Drag & Drop: - Dateien per Drag & Drop auf den Datei-Explorer ziehen - Ganze Ordner (inkl. Unterordner) per Drag & Drop hochladen - Visuelles Overlay zeigt Drop-Zone an - Ordnerstruktur wird automatisch auf dem Server nachgebildet Buttons: - "Dateien" Button: Mehrere Dateien auswaehlen (wie vorher) - "Ordner" Button: Kompletten Ordner mit Unterordnern hochladen (nutzt webkitdirectory API) Upload-Fortschritt: - Fortschrittsbalken mit Datei-Zaehler waehrend des Uploads - Fehlerhafte Uploads werden gezaehlt und gemeldet Backend: /files/ensure-path Endpunkt erstellt verschachtelte Ordnerstrukturen (z.B. "Docs/Work/Project") in einem Aufruf Co-Authored-By: Claude Opus 4.6 (1M context) --- backend/app/api/files.py | 40 ++++++ frontend/src/views/FilesView.vue | 217 +++++++++++++++++++++++++++++-- 2 files changed, 244 insertions(+), 13 deletions(-) diff --git a/backend/app/api/files.py b/backend/app/api/files.py index e871ad8..bde1daa 100644 --- a/backend/app/api/files.py +++ b/backend/app/api/files.py @@ -126,6 +126,46 @@ def create_folder(): return jsonify(folder.to_dict()), 201 +def _ensure_folder_path(user_id, parent_id, path_parts): + """Create nested folder structure. Returns the ID of the deepest folder.""" + current_parent = parent_id + for part in path_parts: + part = part.strip() + if not part: + continue + existing = File.query.filter_by( + owner_id=user_id, parent_id=current_parent, name=part, is_folder=True + ).first() + if existing: + current_parent = existing.id + else: + folder = File(owner_id=user_id, parent_id=current_parent, name=part, is_folder=True) + db.session.add(folder) + db.session.flush() + current_parent = folder.id + return current_parent + + +@api_bp.route('/files/ensure-path', methods=['POST']) +@token_required +def ensure_folder_path(): + """Create nested folder structure from a path string like 'Docs/Work/Project'. + Returns the ID of the deepest folder.""" + user = request.current_user + data = request.get_json() + path = data.get('path', '').strip().strip('/') + parent_id = data.get('parent_id', None) + + if not path: + return jsonify({'folder_id': parent_id}), 200 + + parts = [p for p in path.split('/') if p.strip()] + folder_id = _ensure_folder_path(user.id, parent_id, parts) + db.session.commit() + + return jsonify({'folder_id': folder_id}), 200 + + # --- Upload --- @api_bp.route('/files/upload', methods=['POST']) diff --git a/frontend/src/views/FilesView.vue b/frontend/src/views/FilesView.vue index 59860e6..6914bc9 100644 --- a/frontend/src/views/FilesView.vue +++ b/frontend/src/views/FilesView.vue @@ -1,5 +1,16 @@