diff --git a/app/src/api/api.ts b/app/src/api/api.ts index 6f97c76..f46c0d1 100644 --- a/app/src/api/api.ts +++ b/app/src/api/api.ts @@ -29,10 +29,16 @@ export const apiCall = async ( // Set up headers with CSRF token for non-GET requests const method = options.method || 'GET'; const headers: Record = { - 'Content-Type': 'application/json', ...(options.headers as Record), }; + // Only set Content-Type to application/json if not already set and body is not FormData + // FormData requires the browser to set Content-Type with the boundary parameter + const isFormData = options.body instanceof FormData; + if (!headers['Content-Type'] && !isFormData) { + headers['Content-Type'] = 'application/json'; + } + // Add CSRF token for non-GET methods if (method !== 'GET') { const csrfToken = getCsrfToken(); @@ -41,11 +47,18 @@ export const apiCall = async ( } } + // For FormData, don't include Content-Type in headers - let the browser set it + const fetchHeaders = isFormData + ? Object.fromEntries( + Object.entries(headers).filter(([key]) => key !== 'Content-Type') + ) + : headers; + const response = await fetch(url, { ...options, // Include credentials to send/receive cookies credentials: 'include', - headers, + headers: fetchHeaders, }); console.debug(`Response status: ${response.status} for URL: ${url}`); diff --git a/app/src/hooks/useFileOperations.ts b/app/src/hooks/useFileOperations.ts index 6317c47..dc26607 100644 --- a/app/src/hooks/useFileOperations.ts +++ b/app/src/hooks/useFileOperations.ts @@ -122,7 +122,8 @@ export const useFileOperations = (): UseFileOperationsResult => { if (!currentWorkspace) return false; try { - await uploadFile(currentWorkspace.name, targetPath || '', files); + // Default to '.' (root directory) if no target path is provided + await uploadFile(currentWorkspace.name, targetPath || '.', files); notifications.show({ title: 'Success', diff --git a/server/internal/handlers/file_handlers.go b/server/internal/handlers/file_handlers.go index 33f37e1..5b03858 100644 --- a/server/internal/handlers/file_handlers.go +++ b/server/internal/handlers/file_handlers.go @@ -410,7 +410,8 @@ func (h *Handler) UploadFile() http.HandlerFunc { } }() - filePath := decodedPath + "/" + formFile.Filename + // Use filepath.Join to properly construct the path + filePath := filepath.Join(decodedPath, formFile.Filename) content, err := io.ReadAll(file) if err != nil { diff --git a/server/internal/handlers/file_handlers_integration_test.go b/server/internal/handlers/file_handlers_integration_test.go index 610ebbb..49fe865 100644 --- a/server/internal/handlers/file_handlers_integration_test.go +++ b/server/internal/handlers/file_handlers_integration_test.go @@ -352,15 +352,6 @@ func testFileHandlers(t *testing.T, dbConfig DatabaseConfig) { assert.Equal(t, http.StatusBadRequest, rr.Code) }) - t.Run("upload with missing file_path parameter", func(t *testing.T) { - fileName := "test.txt" - fileContent := "test content" - files := map[string]string{fileName: fileContent} - - rr := h.makeUploadRequest(t, baseURL+"/upload", files, h.RegularTestUser) - assert.Equal(t, http.StatusBadRequest, rr.Code) - }) - t.Run("upload with invalid file_path", func(t *testing.T) { fileName := "test.txt" fileContent := "test content"