From ef8d17b3d957dc814fdff783f49f55a6bb58007e Mon Sep 17 00:00:00 2001 From: Wang Qi Date: Mon, 28 Sep 2026 12:00:57 +0800 Subject: [PATCH] Fix go workspaces APIs (#20272) --- internal/handler/file_commit.go | 59 ++++++++++++++++------------ internal/handler/file_commit_test.go | 8 ++-- internal/router/router.go | 26 ++++++------ 3 files changed, 52 insertions(+), 41 deletions(-) diff --git a/internal/handler/file_commit.go b/internal/handler/file_commit.go index f7f26c4a00..28b93f2929 100644 --- a/internal/handler/file_commit.go +++ b/internal/handler/file_commit.go @@ -142,6 +142,13 @@ func (h *FileCommitHandler) folderAccessible(c *gin.Context, userID, folderID st return service.CheckFileTeamPermission(ctx, h.fileDAO, folder, userID) } +func commitFolderID(c *gin.Context) string { + if folderID := c.Param("folder_id"); folderID != "" { + return folderID + } + return c.Param("workspace_id") +} + // CreateCommitRequest represents the request body for creating a commit type CreateCommitRequest struct { Message string `json:"message" binding:"required"` @@ -152,10 +159,10 @@ type CreateCommitRequest struct { // @Summary Create Commit // @Description Create a new commit with file changes for a workspace folder // @Tags file_commit -// @Param folder_id path string true "workspace folder ID" +// @Param workspace_id path string true "workspace ID" // @Param body body CreateCommitRequest true "commit request" // @Success 200 {object} map[string]interface{} -// @Router /api/v1/workspaces/{folder_id}/commits [post] +// @Router /api/v1/workspaces/{workspace_id}/commits [post] func (h *FileCommitHandler) CreateCommit(c *gin.Context) { user, errorCode, errorMessage := GetUser(c) if errorCode != common.CodeSuccess { @@ -163,7 +170,7 @@ func (h *FileCommitHandler) CreateCommit(c *gin.Context) { return } - folderID := c.Param("folder_id") + folderID := commitFolderID(c) if folderID == "" { common.ResponseWithCodeData(c, common.CodeParamError, nil, "folder_id is required") return @@ -210,13 +217,13 @@ func (h *FileCommitHandler) CreateCommit(c *gin.Context) { // @Tags file_commit // @Accept json // @Produce json -// @Param folder_id path string true "workspace folder ID" +// @Param workspace_id path string true "workspace ID" // @Param page query int false "page number" // @Param page_size query int false "items per page" // @Param order_by query string false "order by field" // @Param desc query bool false "descending order" // @Success 200 {object} map[string]interface{} -// @Router /api/v1/workspaces/{folder_id}/commits [get] +// @Router /api/v1/workspaces/{workspace_id}/commits [get] func (h *FileCommitHandler) ListCommits(c *gin.Context) { user, errorCode, errorMessage := GetUser(c) if errorCode != common.CodeSuccess { @@ -224,7 +231,7 @@ func (h *FileCommitHandler) ListCommits(c *gin.Context) { return } - folderID := c.Param("folder_id") + folderID := commitFolderID(c) if folderID == "" { common.ResponseWithCodeData(c, common.CodeParamError, nil, "folder_id is required") return @@ -331,10 +338,10 @@ func (h *FileCommitHandler) ListCommits(c *gin.Context) { // @Tags file_commit // @Accept json // @Produce json -// @Param folder_id path string true "workspace folder ID" +// @Param workspace_id path string true "workspace ID" // @Param commit_id path string true "commit ID" // @Success 200 {object} map[string]interface{} -// @Router /api/v1/workspaces/{folder_id}/commits/{commit_id} [get] +// @Router /api/v1/workspaces/{workspace_id}/commits/{commit_id} [get] func (h *FileCommitHandler) GetCommit(c *gin.Context) { user, errorCode, errorMessage := GetUser(c) if errorCode != common.CodeSuccess { @@ -342,7 +349,7 @@ func (h *FileCommitHandler) GetCommit(c *gin.Context) { return } - folderID := c.Param("folder_id") + folderID := commitFolderID(c) commitID := c.Param("commit_id") if commitID == "" { common.ResponseWithCodeData(c, common.CodeParamError, nil, "commit_id is required") @@ -406,10 +413,10 @@ func (h *FileCommitHandler) GetCommit(c *gin.Context) { // @Tags file_commit // @Accept json // @Produce json -// @Param folder_id path string true "workspace folder ID" +// @Param workspace_id path string true "workspace ID" // @Param commit_id path string true "commit ID" // @Success 200 {object} map[string]interface{} -// @Router /api/v1/workspaces/{folder_id}/commits/{commit_id}/files [get] +// @Router /api/v1/workspaces/{workspace_id}/commits/{commit_id}/files [get] func (h *FileCommitHandler) ListCommitFiles(c *gin.Context) { user, errorCode, errorMessage := GetUser(c) if errorCode != common.CodeSuccess { @@ -417,7 +424,7 @@ func (h *FileCommitHandler) ListCommitFiles(c *gin.Context) { return } - folderID := c.Param("folder_id") + folderID := commitFolderID(c) commitID := c.Param("commit_id") if commitID == "" { common.ResponseWithCodeData(c, common.CodeParamError, nil, "commit_id is required") @@ -454,11 +461,11 @@ func (h *FileCommitHandler) ListCommitFiles(c *gin.Context) { // @Tags file_commit // @Accept json // @Produce json -// @Param folder_id path string true "workspace folder ID" +// @Param workspace_id path string true "workspace ID" // @Param from query string true "from commit ID" // @Param to query string true "to commit ID" // @Success 200 {object} map[string]interface{} -// @Router /api/v1/workspaces/{folder_id}/commits/diff [get] +// @Router /api/v1/workspaces/{workspace_id}/commits/diff [get] func (h *FileCommitHandler) DiffCommits(c *gin.Context) { user, errorCode, errorMessage := GetUser(c) if errorCode != common.CodeSuccess { @@ -466,7 +473,7 @@ func (h *FileCommitHandler) DiffCommits(c *gin.Context) { return } - folderID := c.Param("folder_id") + folderID := commitFolderID(c) fromID := c.Query("from") toID := c.Query("to") if fromID == "" || toID == "" { @@ -509,9 +516,9 @@ func (h *FileCommitHandler) DiffCommits(c *gin.Context) { // @Tags file_commit // @Accept json // @Produce json -// @Param folder_id path string true "workspace folder ID" +// @Param workspace_id path string true "workspace ID" // @Success 200 {object} map[string]interface{} -// @Router /api/v1/workspaces/{folder_id}/changes [get] +// @Router /api/v1/workspaces/{workspace_id}/changes [get] func (h *FileCommitHandler) GetUncommittedChanges(c *gin.Context) { user, errorCode, errorMessage := GetUser(c) if errorCode != common.CodeSuccess { @@ -519,7 +526,7 @@ func (h *FileCommitHandler) GetUncommittedChanges(c *gin.Context) { return } - folderID := c.Param("folder_id") + folderID := commitFolderID(c) if folderID == "" { common.ResponseWithCodeData(c, common.CodeParamError, nil, "folder_id is required") return @@ -545,10 +552,10 @@ func (h *FileCommitHandler) GetUncommittedChanges(c *gin.Context) { // @Tags file_commit // @Accept json // @Produce json -// @Param folder_id path string true "workspace folder ID" +// @Param workspace_id path string true "workspace ID" // @Param commit_id path string true "commit ID" // @Success 200 {object} map[string]interface{} -// @Router /api/v1/workspaces/{folder_id}/commits/{commit_id}/tree [get] +// @Router /api/v1/workspaces/{workspace_id}/commits/{commit_id}/tree [get] func (h *FileCommitHandler) GetCommitTree(c *gin.Context) { user, errorCode, errorMessage := GetUser(c) if errorCode != common.CodeSuccess { @@ -556,7 +563,7 @@ func (h *FileCommitHandler) GetCommitTree(c *gin.Context) { return } - folderID := c.Param("folder_id") + folderID := commitFolderID(c) commitID := c.Param("commit_id") if commitID == "" { common.ResponseWithCodeData(c, common.CodeParamError, nil, "commit_id is required") @@ -593,11 +600,11 @@ func (h *FileCommitHandler) GetCommitTree(c *gin.Context) { // @Tags file_commit // @Accept json // @Produce json -// @Param folder_id path string true "workspace folder ID" +// @Param workspace_id path string true "workspace ID" // @Param commit_id path string true "commit ID" // @Param file_id path string true "file ID" // @Success 200 {object} map[string]interface{} -// @Router /api/v1/workspaces/{folder_id}/commits/{commit_id}/files/{file_id}/content [get] +// @Router /api/v1/workspaces/{workspace_id}/commits/{commit_id}/files/{file_id}/content [get] func (h *FileCommitHandler) GetCommitFileContent(c *gin.Context) { user, errorCode, errorMessage := GetUser(c) if errorCode != common.CodeSuccess { @@ -605,7 +612,7 @@ func (h *FileCommitHandler) GetCommitFileContent(c *gin.Context) { return } - folderID := c.Param("folder_id") + folderID := commitFolderID(c) commitID := c.Param("commit_id") fileID := c.Param("file_id") @@ -646,7 +653,7 @@ func (h *FileCommitHandler) GetCommitFileContent(c *gin.Context) { // @Produce json // @Param file_id path string true "file ID" // @Success 200 {object} map[string]interface{} -// @Router /api/v1/files/{file_id}/versions [get] +// @Router /api/v1/workspace-files/{file_id}/versions [get] func (h *FileCommitHandler) GetFileVersionHistory(c *gin.Context) { user, errorCode, errorMessage := GetUser(c) if errorCode != common.CodeSuccess { @@ -654,7 +661,7 @@ func (h *FileCommitHandler) GetFileVersionHistory(c *gin.Context) { return } - fileID := c.Param("id") + fileID := c.Param("file_id") if fileID == "" { common.ResponseWithCodeData(c, common.CodeParamError, nil, "file_id is required") return diff --git a/internal/handler/file_commit_test.go b/internal/handler/file_commit_test.go index 83d3226781..cf7f63c22b 100644 --- a/internal/handler/file_commit_test.go +++ b/internal/handler/file_commit_test.go @@ -198,7 +198,7 @@ func fileCommitRouter(h *FileCommitHandler, userID string) *gin.Engine { r.GET("/api/v1/folders/:folder_id/changes", h.GetUncommittedChanges) r.GET("/api/v1/folders/:folder_id/commits/:commit_id/tree", h.GetCommitTree) r.GET("/api/v1/folders/:folder_id/commits/:commit_id/files/:file_id/content", h.GetCommitFileContent) - r.GET("/api/v1/files/:id/versions", h.GetFileVersionHistory) + r.GET("/api/v1/workspace-files/:file_id/versions", h.GetFileVersionHistory) // Mirrors the CommitFolderResolver middleware used on the production // /datasets/{dataset_id}/commits route: dataset_id resolves to folder_id. r.GET("/api/v1/datasets/:dataset_id/commits", func(c *gin.Context) { @@ -641,7 +641,7 @@ func TestFileCommit_GetFileVersionHistory_Success(t *testing.T) { r, _ := setupFileCommitTest("user-1") w := httptest.NewRecorder() - req, _ := http.NewRequest("GET", "/api/v1/files/f1/versions", nil) + req, _ := http.NewRequest("GET", "/api/v1/workspace-files/f1/versions", nil) r.ServeHTTP(w, req) var resp map[string]interface{} @@ -681,7 +681,7 @@ func TestFileCommit_ForeignFolderRejected(t *testing.T) { {"GET", "/api/v1/folders/folder-1/commits/commit-1/files/f1/content", ""}, {"GET", "/api/v1/folders/folder-1/commits/diff?from=c1&to=c2", ""}, {"POST", "/api/v1/folders/folder-1/commits", `{"message": "x", "files": [{"file_id": "f1", "file_name": "t", "operation": "add", "content": "c"}]}`}, - {"GET", "/api/v1/files/f1/versions", ""}, + {"GET", "/api/v1/workspace-files/f1/versions", ""}, } for _, e := range endpoints { @@ -722,7 +722,7 @@ func TestFileCommit_OwnFolderStillWorks(t *testing.T) { } w = httptest.NewRecorder() - req, _ = http.NewRequest("GET", "/api/v1/files/f1/versions", nil) + req, _ = http.NewRequest("GET", "/api/v1/workspace-files/f1/versions", nil) r.ServeHTTP(w, req) if code := decodeCode(t, w); code != float64(common.CodeSuccess) { t.Errorf("expected code %d for owner version history, got %v: %s", common.CodeSuccess, code, w.Body.String()) diff --git a/internal/router/router.go b/internal/router/router.go index 60ad3bdce9..18b3467b9b 100644 --- a/internal/router/router.go +++ b/internal/router/router.go @@ -450,7 +450,11 @@ func (r *Router) Setup(engine *gin.Engine) { files.GET("/:id/ancestors", r.fileHandler.GetFileAncestors) files.GET("/:id/parent", r.fileHandler.GetParentFolder) files.GET("/:id", r.fileHandler.Download) - files.GET("/:id/versions", r.fileCommitHandler.GetFileVersionHistory) + } + + workspaceFiles := v1.Group("/workspace-files") + { + workspaceFiles.GET("/:file_id/versions", r.fileCommitHandler.GetFileVersionHistory) } // File routes @@ -474,17 +478,17 @@ func (r *Router) Setup(engine *gin.Engine) { commitFolders.GET("/:folder_id/changes", r.fileCommitHandler.GetUncommittedChanges) } - // /workspace/{workspace_id}/commits — alias for /folders/ (workspace_id == folder_id) - commitWorkspace := v1.Group("/workspace") + // /workspaces/{workspace_id}/commits — alias for /folders/ (workspace_id == folder_id) + commitWorkspaces := v1.Group("/workspaces") { - commitWorkspace.POST("/:folder_id/commits", r.fileCommitHandler.CreateCommit) - commitWorkspace.GET("/:folder_id/commits", r.fileCommitHandler.ListCommits) - commitWorkspace.GET("/:folder_id/commits/diff", r.fileCommitHandler.DiffCommits) - commitWorkspace.GET("/:folder_id/commits/:commit_id", r.fileCommitHandler.GetCommit) - commitWorkspace.GET("/:folder_id/commits/:commit_id/files", r.fileCommitHandler.ListCommitFiles) - commitWorkspace.GET("/:folder_id/commits/:commit_id/tree", r.fileCommitHandler.GetCommitTree) - commitWorkspace.GET("/:folder_id/commits/:commit_id/files/:file_id/content", r.fileCommitHandler.GetCommitFileContent) - commitWorkspace.GET("/:folder_id/changes", r.fileCommitHandler.GetUncommittedChanges) + commitWorkspaces.POST("/:workspace_id/commits", r.fileCommitHandler.CreateCommit) + commitWorkspaces.GET("/:workspace_id/commits", r.fileCommitHandler.ListCommits) + commitWorkspaces.GET("/:workspace_id/commits/diff", r.fileCommitHandler.DiffCommits) + commitWorkspaces.GET("/:workspace_id/commits/:commit_id", r.fileCommitHandler.GetCommit) + commitWorkspaces.GET("/:workspace_id/commits/:commit_id/files", r.fileCommitHandler.ListCommitFiles) + commitWorkspaces.GET("/:workspace_id/commits/:commit_id/tree", r.fileCommitHandler.GetCommitTree) + commitWorkspaces.GET("/:workspace_id/commits/:commit_id/files/:file_id/content", r.fileCommitHandler.GetCommitFileContent) + commitWorkspaces.GET("/:workspace_id/changes", r.fileCommitHandler.GetUncommittedChanges) } // /datasets/{dataset_id}/commits — resolve dataset_id → folder_id via middleware