From 49374eede38017ca8851aece063eb22414e632d3 Mon Sep 17 00:00:00 2001 From: maoyifeng Date: Tue, 21 Jul 2026 16:46:45 +0800 Subject: [PATCH] Go cli: fix list users failed: invalid JSON (unexpected end of JSON ) (#17153) ### Summary Go cli: fix list users failed: invalid JSON (unexpected end of JSON ) --- internal/admin/handler.go | 27 ++++++++++++------ internal/admin/service_ee.go | 8 ++++-- internal/cli/admin_command.go | 54 +++++++++++++---------------------- 3 files changed, 44 insertions(+), 45 deletions(-) diff --git a/internal/admin/handler.go b/internal/admin/handler.go index 835d19ca19..59e416c527 100644 --- a/internal/admin/handler.go +++ b/internal/admin/handler.go @@ -191,14 +191,21 @@ func (h *Handler) ListUsers(c *gin.Context) { common.ErrorWithCode(c, common.CodeBadRequest, err.Error()) return } - quotaInt, err := common.ParseRequestIntPositive(c, c.Query("quota"), "quota", 0) - if err != nil { - common.ErrorWithCode(c, common.CodeBadRequest, err.Error()) - return - } - if quotaInt > 100 { - common.ErrorWithCode(c, common.CodeBadRequest, "Quota must be less than or equal to 100") - return + // quota is optional: nil when the query param is absent, &v when present + // (including 0). This lets ListUsersEE distinguish "no quota filter" from + // "filter by quota threshold 0". + var quotaPtr *int + if quotaStr := c.Query("quota"); quotaStr != "" { + q, err := common.ParseRequestIntPositive(c, quotaStr, "quota", 0) + if err != nil { + common.ErrorWithCode(c, common.CodeBadRequest, err.Error()) + return + } + if q > 100 { + common.ErrorWithCode(c, common.CodeBadRequest, "Quota must be less than or equal to 100") + return + } + quotaPtr = &q } daysInt, err := common.ParseRequestIntPositive(c, c.Query("days"), "days", 0) if err != nil { @@ -219,11 +226,13 @@ func (h *Handler) ListUsers(c *gin.Context) { common.SuccessWithData(c, users, "List users") return case common.EnterpriseEdition: - users, err = h.service.ListUsersEE(pageInt, pageSizeInt, name, status, role, sort, orderBy, plan, topInt, daysInt, quotaInt) + users, err = h.service.ListUsersEE(pageInt, pageSizeInt, name, status, role, sort, orderBy, plan, topInt, daysInt, quotaPtr) if err != nil { common.ErrorWithCode(c, common.CodeServerError, err.Error()) return } + common.SuccessWithData(c, users, "List users") + return default: common.ErrorWithCode(c, common.CodeBadRequest, "Invalid RAGFlow type") return diff --git a/internal/admin/service_ee.go b/internal/admin/service_ee.go index 2bfa52d9ee..75535d771c 100644 --- a/internal/admin/service_ee.go +++ b/internal/admin/service_ee.go @@ -788,7 +788,7 @@ func (s *Service) ShowUsersActivity(days, windows *int) (map[string]interface{}, return result, nil } -func (s *Service) ListUsersEE(pageIndex, pageSize int, name string, status, role, sort, orderBy, plan string, top, days, quota int) ([]map[string]interface{}, error) { +func (s *Service) ListUsersEE(pageIndex, pageSize int, name string, status, role, sort, orderBy, plan string, top, days int, quota *int) ([]map[string]interface{}, error) { item := map[string]interface{}{} item["pageIndex"] = pageIndex item["pageSize"] = pageSize @@ -800,7 +800,11 @@ func (s *Service) ListUsersEE(pageIndex, pageSize int, name string, status, role item["plan"] = plan item["top"] = top item["days"] = days - item["quota"] = quota + quotaInt := 0 + if quota != nil { + quotaInt = *quota + } + item["quota"] = quotaInt var result []map[string]interface{} result = append(result, item) diff --git a/internal/cli/admin_command.go b/internal/cli/admin_command.go index ec13173aa6..27959de0ee 100644 --- a/internal/cli/admin_command.go +++ b/internal/cli/admin_command.go @@ -1881,49 +1881,35 @@ func (c *CLI) AdminListUsersConditionCommand(cmd *Command) (ResponseIf, error) { return nil, fmt.Errorf("this command is only allowed in ADMIN mode or already login") } - var orderBy *string - var userStatus *string - var top *int - var plan *string - var quota *int - var days *int - - orderByStr, ok := cmd.Params["order_by"].(string) - if ok { - orderBy = &orderByStr + // Server-side ListUsers reads these via c.Query(), so GET parameters must + // travel in the URL query string, not the request body. Parameter names + // must match the server-side query keys (e.g. "order" not "order_by"). + q := url.Values{} + if orderByStr, ok := cmd.Params["order_by"].(string); ok { + q.Set("order", orderByStr) } - userStatusStr, ok := cmd.Params["user_status"].(string) - if ok { - userStatus = &userStatusStr + if userStatusStr, ok := cmd.Params["user_status"].(string); ok { + q.Set("status", userStatusStr) } - topInt, ok := cmd.Params["top"].(int) - if ok { - top = &topInt + if topInt, ok := cmd.Params["top"].(int); ok { + q.Set("top", fmt.Sprintf("%d", topInt)) } - planStr, ok := cmd.Params["plan"].(string) - if ok { - plan = &planStr + if planStr, ok := cmd.Params["plan"].(string); ok { + q.Set("plan", planStr) } - quotaInt, ok := cmd.Params["quota"].(int) - if ok { - quota = "aInt + if quotaInt, ok := cmd.Params["quota"].(int); ok { + q.Set("quota", fmt.Sprintf("%d", quotaInt)) } - daysInt, ok := cmd.Params["days"].(int) - if ok { - days = &daysInt + if daysInt, ok := cmd.Params["days"].(int); ok { + q.Set("days", fmt.Sprintf("%d", daysInt)) } - payload := map[string]interface{}{ - "enterprise": true, - "order_by": orderBy, - "user_status": userStatus, - "top": top, - "plan": plan, - "quota": quota, - "days": days, + apiURL := "/admin/users" + if encoded := q.Encode(); encoded != "" { + apiURL = fmt.Sprintf("%s?%s", apiURL, encoded) } - resp, err := c.AdminServerClient.Request("GET", "/admin/users", "admin", nil, payload) + resp, err := c.AdminServerClient.Request("GET", apiURL, "admin", nil, nil) if err != nil { return nil, fmt.Errorf("failed to list users: %w", err) }