From ae8c18bb17ea139fa2f692e6def29d7b28bb84ed Mon Sep 17 00:00:00 2001 From: Haruko386 Date: Fri, 31 Jul 2026 20:14:35 +0800 Subject: [PATCH] fix: team member can edit permission (#17633) ### Summary As title --- internal/handler/agent.go | 2 +- internal/router/router.go | 6 ---- internal/service/agent.go | 11 +++++-- internal/service/agent_test.go | 60 ++++++++++++++++++++++++++++++++++ 4 files changed, 69 insertions(+), 10 deletions(-) diff --git a/internal/handler/agent.go b/internal/handler/agent.go index 6b451f4fe9..df2301ff5d 100644 --- a/internal/handler/agent.go +++ b/internal/handler/agent.go @@ -389,7 +389,7 @@ func (h *AgentHandler) UpdateAgent(c *gin.Context) { if req == nil { req = updateAgentRequest{} } - if err := h.agentService.UpdateAgent(c.Request.Context(), user.ID, canvasID, map[string]interface{}(req)); err != nil { + if err := h.agentService.UpdateAgent(c.Request.Context(), user.ID, canvasID, req); err != nil { ec, em := mapAgentError(err) common.ResponseWithCodeData(c, ec, nil, em) return diff --git a/internal/router/router.go b/internal/router/router.go index d6c46440da..5b6115fa19 100644 --- a/internal/router/router.go +++ b/internal/router/router.go @@ -149,12 +149,6 @@ func (r *Router) Setup(engine *gin.Engine) { // User logout endpoint engine.GET("/v1/user/logout", r.userHandler.Logout) - // OAuth callbacks are invoked by third-party providers and cannot rely on - // the RAGFlow auth middleware. - engine.GET("/connectors/gmail/oauth/web/callback", r.connectorHandler.GmailWebOAuthCallback) - engine.GET("/connectors/google-drive/oauth/web/callback", r.connectorHandler.GoogleDriveWebOAuthCallback) - engine.GET("/connectors/box/oauth/web/callback", r.connectorHandler.BoxWebOAuthCallback) - apiNoAuth := engine.Group("/api/v1") { apiNoAuth.GET("/system/ping", r.systemHandler.Ping) diff --git a/internal/service/agent.go b/internal/service/agent.go index c8a4cd74ad..1e58692119 100644 --- a/internal/service/agent.go +++ b/internal/service/agent.go @@ -698,9 +698,14 @@ func (s *AgentService) UpdateAgent(ctx context.Context, userID, canvasID string, if err != nil { return err } + ownerUserID := canvasInstance.UserID - // Only the canvas owner may change the permission field. - if _, ok := patch["permission"]; ok && canvasInstance.UserID != userID { + if v, ok := patch["permission"]; ok && ownerUserID != userID { + requested := strings.ToLower(strings.TrimSpace(fmt.Sprint(v))) + current := strings.ToLower(strings.TrimSpace(canvasInstance.Permission)) + if requested != current { + return fmt.Errorf("user %s has no permission to edit permission", userID) + } delete(patch, "permission") } @@ -734,7 +739,7 @@ func (s *AgentService) UpdateAgent(ctx context.Context, userID, canvasID string, updates["release"] = release if title, ok := updatedAgentTitle(canvasInstance, updates); ok { canvasCategory := updatedAgentCanvasCategory(canvasInstance, updates) - if existing, err := s.canvasDAO.GetByUserAndTitle(ctx, dao.DB, userID, title, canvasCategory); err != nil { + if existing, err := s.canvasDAO.GetByUserAndTitle(ctx, dao.DB, ownerUserID, title, canvasCategory); err != nil { return fmt.Errorf("check duplicate title: %w", err) } else if existing != nil && existing.ID != canvasID { return agentTitleAlreadyExistsError(title) diff --git a/internal/service/agent_test.go b/internal/service/agent_test.go index a64b6a3501..c984777f8a 100644 --- a/internal/service/agent_test.go +++ b/internal/service/agent_test.go @@ -1518,6 +1518,66 @@ func TestUpdateAgentAllowsExistingTitleForSameCanvas(t *testing.T) { } } +func TestUpdateAgentTeamMemberPermissionAndOwnerTitleChecks(t *testing.T) { + setupAgentSessionServiceTest(t) + ctx := t.Context() + + status := "1" + for _, row := range []*entity.UserCanvas{ + { + ID: "canvas-team-edit", + UserID: "owner-1", + Title: sptr("Editable Title"), + Permission: string(entity.TenantPermissionTeam), + CanvasCategory: "agent_canvas", + DSL: entity.JSONMap{}, + }, + { + ID: "canvas-owner-duplicate", + UserID: "owner-1", + Title: sptr("Owner Duplicate"), + Permission: string(entity.TenantPermissionMe), + CanvasCategory: "agent_canvas", + DSL: entity.JSONMap{}, + }, + } { + if err := dao.DB.WithContext(ctx).Create(row).Error; err != nil { + t.Fatalf("failed to seed canvas %s: %v", row.ID, err) + } + } + if err := dao.DB.WithContext(ctx).Create(&entity.UserTenant{ + ID: "ut-agent-team", + UserID: "member-1", + TenantID: "owner-1", + Role: "normal", + InvitedBy: "owner-1", + Status: &status, + }).Error; err != nil { + t.Fatalf("failed to seed user tenant: %v", err) + } + + samePermission := " TEAM " + if err := NewAgentService().UpdateAgent(ctx, "member-1", "canvas-team-edit", map[string]interface{}{ + "description": "member edit", + "permission": samePermission, + }); err != nil { + t.Fatalf("UpdateAgent with same permission failed: %v", err) + } + + nextPermission := "me" + if err := NewAgentService().UpdateAgent(ctx, "member-1", "canvas-team-edit", map[string]interface{}{ + "permission": nextPermission, + }); err == nil { + t.Fatal("UpdateAgent permission change error = nil, want error") + } + + if err := NewAgentService().UpdateAgent(ctx, "member-1", "canvas-team-edit", map[string]interface{}{ + "title": "Owner Duplicate", + }); err == nil || err.Error() != "Owner Duplicate already exists." { + t.Fatalf("UpdateAgent duplicate title error = %v, want Owner Duplicate already exists.", err) + } +} + func TestUpdateAgentRejectsDuplicateTitleInDestinationCategory(t *testing.T) { setupAgentSessionServiceTest(t) ctx := t.Context()