diff --git a/b0esche_cloud/lib/blocs/upload/upload_bloc.dart b/b0esche_cloud/lib/blocs/upload/upload_bloc.dart index 4a21e9c..7681bb3 100644 --- a/b0esche_cloud/lib/blocs/upload/upload_bloc.dart +++ b/b0esche_cloud/lib/blocs/upload/upload_bloc.dart @@ -24,10 +24,14 @@ class UploadBloc extends Bloc { for (final file in event.files) { try { + print('[UploadBloc] Starting upload for ${file.name} to orgId=${event.orgId}, path=${file.path}'); + print('[UploadBloc] File bytes: ${file.bytes?.length ?? 0} bytes, localPath: ${file.localPath}'); // Simulate upload await _fileRepository.uploadFile(event.orgId, file); + print('[UploadBloc] Upload successful for ${file.name}'); add(UploadCompleted(file)); } catch (e) { + print('[UploadBloc] Upload failed for ${file.name}: $e'); add(UploadFailed(fileName: file.name, error: e.toString())); } } diff --git a/b0esche_cloud/lib/pages/file_explorer.dart b/b0esche_cloud/lib/pages/file_explorer.dart index 48609af..24df38d 100644 --- a/b0esche_cloud/lib/pages/file_explorer.dart +++ b/b0esche_cloud/lib/pages/file_explorer.dart @@ -665,6 +665,14 @@ class _FileExplorerState extends State { return BlocListener( listener: (context, uploadState) { if (uploadState is UploadInProgress) { + // Show error if any upload failed + for (final upload in uploadState.uploads) { + if (upload.error != null && upload.error!.isNotEmpty) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text('Upload failed: ${upload.error}')), + ); + } + } final hasCompleted = uploadState.uploads.any((u) => u.isCompleted); if (hasCompleted) { final fbState = context.read().state; diff --git a/b0esche_cloud/lib/services/file_service.dart b/b0esche_cloud/lib/services/file_service.dart index fe1812b..fbd8906 100644 --- a/b0esche_cloud/lib/services/file_service.dart +++ b/b0esche_cloud/lib/services/file_service.dart @@ -52,18 +52,24 @@ class FileService { // If bytes or localPath available, send multipart upload with field 'file' final Map fields = {'path': file.path}; FormData formData; + print('[FileService] uploadFile: file=${file.name}, path=${file.path}, orgId=$orgId'); + print('[FileService] bytes=${file.bytes?.length ?? 0}, localPath=${file.localPath}'); + if (file.bytes != null) { + print('[FileService] Using bytes for upload (${file.bytes!.length} bytes)'); formData = FormData.fromMap({ ...fields, 'file': MultipartFile.fromBytes(file.bytes!, filename: file.name), }); } else if (file.localPath != null) { + print('[FileService] Using localPath for upload: ${file.localPath}'); formData = FormData.fromMap({ ...fields, 'file': MultipartFile.fromFile(file.localPath!, filename: file.name), }); } else { // Fallback to metadata-only create (folders or client that can't send file content) + print('[FileService] No bytes or localPath; falling back to metadata-only'); final data = { 'name': file.name, 'path': file.path, @@ -82,19 +88,14 @@ class FileService { return; } - if (orgId.isEmpty) { - await _apiClient.post( - '/user/files', - data: formData, - fromJson: (d) => null, - ); - return; - } + final endpoint = orgId.isEmpty ? '/user/files' : '/orgs/$orgId/files'; + print('[FileService] Uploading to endpoint: $endpoint'); await _apiClient.post( - '/orgs/$orgId/files', + endpoint, data: formData, fromJson: (d) => null, ); + print('[FileService] Upload completed for ${file.name}'); } Future deleteFile(String orgId, String path) async { diff --git a/go_cloud/api b/go_cloud/api index adf1425..c5781c7 100755 Binary files a/go_cloud/api and b/go_cloud/api differ diff --git a/go_cloud/internal/http/routes.go b/go_cloud/internal/http/routes.go index f3f6a7e..3cef112 100644 --- a/go_cloud/internal/http/routes.go +++ b/go_cloud/internal/http/routes.go @@ -968,17 +968,17 @@ func createOrgFileHandler(w http.ResponseWriter, r *http.Request, db *database.D } } - // Fallback: Save to disk under data/uploads/orgs// - baseDir := filepath.Join("data", "uploads", "orgs", orgID.String()) + // Fallback: Save to temp directory (WebDAV should be the primary storage) + baseDir := filepath.Join("/tmp", "uploads", "orgs", orgID.String()) targetDir := filepath.Join(baseDir, parentPath) if err = os.MkdirAll(targetDir, 0o755); err != nil { - errors.LogError(r, err, "Failed to create target dir") + errors.LogError(r, err, "Failed to create target dir in /tmp") errors.WriteError(w, errors.CodeInternal, "Server error", http.StatusInternalServerError) return } outPath := filepath.Join(targetDir, header.Filename) if err = os.WriteFile(outPath, data, 0o644); err != nil { - errors.LogError(r, err, "Failed to write file") + errors.LogError(r, err, "Failed to write file to /tmp") errors.WriteError(w, errors.CodeInternal, "Server error", http.StatusInternalServerError) return } @@ -1148,17 +1148,17 @@ func createUserFileHandler(w http.ResponseWriter, r *http.Request, db *database. } } - // Fallback: write to disk - baseDir := filepath.Join("data", "uploads", "users", userID.String()) + // Fallback: write to temp directory (WebDAV should be the primary storage) + baseDir := filepath.Join("/tmp", "uploads", "users", userID.String()) targetDir := filepath.Join(baseDir, parentPath) if err = os.MkdirAll(targetDir, 0o755); err != nil { - errors.LogError(r, err, "Failed to create target dir") + errors.LogError(r, err, "Failed to create target dir in /tmp") errors.WriteError(w, errors.CodeInternal, "Server error", http.StatusInternalServerError) return } outPath := filepath.Join(targetDir, header.Filename) if err = os.WriteFile(outPath, data, 0o644); err != nil { - errors.LogError(r, err, "Failed to create file") + errors.LogError(r, err, "Failed to write file to /tmp") errors.WriteError(w, errors.CodeInternal, "Server error", http.StatusInternalServerError) return }