From 3ac657486c7ec54c214db49ceb1eef1b2f44b32c Mon Sep 17 00:00:00 2001 From: LordMathis Date: Sat, 12 Jul 2025 11:52:51 +0200 Subject: [PATCH] Implement MoveFile functionality --- server/internal/handlers/file_handlers.go | 65 ++++++++++++++++++++++- server/internal/storage/files.go | 2 +- server/internal/storage/filesystem.go | 6 +++ 3 files changed, 70 insertions(+), 3 deletions(-) diff --git a/server/internal/handlers/file_handlers.go b/server/internal/handlers/file_handlers.go index b04fe09..b5695cc 100644 --- a/server/internal/handlers/file_handlers.go +++ b/server/internal/handlers/file_handlers.go @@ -423,8 +423,69 @@ func (h *Handler) MoveFile() http.HandlerFunc { "workspaceID", ctx.Workspace.ID, "clientIP", r.RemoteAddr, ) - // TODO: Implement MoveFile functionality - _ = log // Suppress unused variable warning + + srcPath := r.URL.Query().Get("src_path") + destPath := r.URL.Query().Get("dest_path") + if srcPath == "" || destPath == "" { + log.Debug("missing src_path or dest_path parameter") + respondError(w, "src_path and dest_path are required", http.StatusBadRequest) + return + } + + // URL-decode the source and destination paths + decodedSrcPath, err := url.PathUnescape(srcPath) + if err != nil { + log.Error("failed to decode source file path", + "srcPath", srcPath, + "error", err.Error(), + ) + respondError(w, "Invalid source file path", http.StatusBadRequest) + return + } + + decodedDestPath, err := url.PathUnescape(destPath) + if err != nil { + log.Error("failed to decode destination file path", + "destPath", destPath, + "error", err.Error(), + ) + respondError(w, "Invalid destination file path", http.StatusBadRequest) + return + } + + err = h.Storage.MoveFile(ctx.UserID, ctx.Workspace.ID, decodedSrcPath, decodedDestPath) + if err != nil { + if storage.IsPathValidationError(err) { + log.Error("invalid file path attempted", + "srcPath", decodedSrcPath, + "destPath", decodedDestPath, + "error", err.Error(), + ) + respondError(w, "Invalid file path", http.StatusBadRequest) + return + } + if os.IsNotExist(err) { + log.Debug("file not found", + "srcPath", decodedSrcPath, + ) + respondError(w, "File not found", http.StatusNotFound) + return + } + log.Error("failed to move file", + "srcPath", decodedSrcPath, + "destPath", decodedDestPath, + "error", err.Error(), + ) + respondError(w, "Failed to move file", http.StatusInternalServerError) + return + } + + response := SaveFileResponse{ + FilePath: decodedDestPath, + Size: -1, // Size is not applicable for move operation + UpdatedAt: time.Now().UTC(), + } + respondJSON(w, response) } } diff --git a/server/internal/storage/files.go b/server/internal/storage/files.go index 867e33d..3d91d8b 100644 --- a/server/internal/storage/files.go +++ b/server/internal/storage/files.go @@ -192,7 +192,7 @@ func (s *Service) MoveFile(userID, workspaceID int, srcPath string, dstPath stri } if err := s.fs.MoveFile(srcFullPath, dstFullPath); err != nil { - return fmt.Errorf("failed to move file: %w", err) + return err } log.Debug("file moved", diff --git a/server/internal/storage/filesystem.go b/server/internal/storage/filesystem.go index 5350859..1aaed4c 100644 --- a/server/internal/storage/filesystem.go +++ b/server/internal/storage/filesystem.go @@ -41,6 +41,12 @@ func (f *osFS) WriteFile(path string, data []byte, perm fs.FileMode) error { // MoveFile moves the file from src to dst, overwriting if necessary. func (f *osFS) MoveFile(src, dst string) error { + _, err := os.Stat(src) + if err != nil { + if os.IsNotExist(err) { + return os.ErrNotExist + } + } if err := os.Rename(src, dst); err != nil { if os.IsExist(err) { // If the destination exists, remove it and try again