diff --git a/cmd/ragflow_server.go b/cmd/ragflow_server.go index e6ed31031d..83575597f8 100644 --- a/cmd/ragflow_server.go +++ b/cmd/ragflow_server.go @@ -221,7 +221,7 @@ func main() { } if arguments.versionFlag { - fmt.Printf("RAGFlow version: %s\n", utility.GetRAGFlowVersion()) + fmt.Printf("RAGFlow version: %s\n", common.GetRAGFlowVersion()) return } @@ -449,7 +449,7 @@ func runAdmin(args *serverArgs) error { " /_/ |_/_/ |_\\____/_/ /_/\\____/|__/|__/ /_/ |_\\__,_/_/ /_/ /_/_/_/ /_/ \n") // Print RAGFlow version - common.Info(fmt.Sprintf("RAGFlow admin version: %s", utility.GetRAGFlowVersion())) + common.Info(fmt.Sprintf("RAGFlow admin version: %s", common.GetRAGFlowVersion())) // Start HTTP server in a goroutine go func() { @@ -509,7 +509,7 @@ func runIngestor(args *serverArgs) error { " /____/\n") // Print RAGFlow version - common.Info(fmt.Sprintf("RAGFlow ingestion service version: %s", utility.GetRAGFlowVersion())) + common.Info(fmt.Sprintf("RAGFlow ingestion service version: %s", common.GetRAGFlowVersion())) // Get local IP address for heartbeat reporting localIP, err := utility.GetLocalIP() @@ -584,7 +584,7 @@ func runSyncer(args *serverArgs) error { " /____/ \n") // Print RAGFlow version - common.Info(fmt.Sprintf("RAGFlow file syncer service version: %s", utility.GetRAGFlowVersion())) + common.Info(fmt.Sprintf("RAGFlow file syncer service version: %s", common.GetRAGFlowVersion())) // Get local IP address for heartbeat reporting localIP, err := utility.GetLocalIP() @@ -863,7 +863,7 @@ func startServer(config *server.Config) { " / _, _// ___ |/ /_/ // __/ / // /_/ /| |/ |/ /\n" + " /_/ |_|/_/ |_|\\____//_/ /_/ \\____/ |__/|__/\n", ) - common.Info(fmt.Sprintf("RAGFlow Go Version: %s", utility.GetRAGFlowVersion())) + common.Info(fmt.Sprintf("RAGFlow Go Version: %s", common.GetRAGFlowVersion())) common.Info(fmt.Sprintf("Server starting on port: %d", config.Server.Port)) if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { common.Fatal("Failed to start server", zap.Error(err)) diff --git a/internal/admin/handler.go b/internal/admin/handler.go index 6ca1402c39..7209001605 100644 --- a/internal/admin/handler.go +++ b/internal/admin/handler.go @@ -84,7 +84,7 @@ func (h *Handler) Ping(c *gin.Context) { // Login handle admin login // @Summary Admin Login -// @Description Admin login verification using email, only superuser can login +// @Description Admin login verification using email, only superuser can log in // @Tags admin // @Accept json // @Produce json @@ -170,51 +170,66 @@ type ListUsersRequest struct { // ListUsers handle list users func (h *Handler) ListUsers(c *gin.Context) { - var err error - var pageInt int - page := c.Param("page") - if page == "" { - pageInt = 0 - } else { - pageInt, err = strconv.Atoi(page) - if err != nil { - common.ErrorWithCode(c, common.CodeBadRequest, "Page must be an integer") - return - } + name := c.DefaultQuery("keyword", "") + status := c.DefaultQuery("status", "") + role := c.DefaultQuery("role", "") + sort := c.DefaultQuery("sort", "") // descending or ascending + orderBy := c.DefaultQuery("order", "") // order by field + pageInt, err := common.ParseRequestIntPositive(c, c.Query("page"), "page", 1) + if err != nil { + common.ErrorWithCode(c, common.CodeBadRequest, err.Error()) + return + } + pageSizeInt, err := common.ParseRequestIntPositive(c, c.Query("page_size"), "page_size", 10) + if err != nil { + common.ErrorWithCode(c, common.CodeBadRequest, err.Error()) + return + } + plan := c.Query("plan") // plan name + topInt, err := common.ParseRequestIntPositive(c, c.Query("top"), "top", 0) + if err != nil { + 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 + } + daysInt, err := common.ParseRequestIntPositive(c, c.Query("days"), "days", 0) + if err != nil { + common.ErrorWithCode(c, common.CodeBadRequest, err.Error()) + return } - var pageSizeInt int - pageSize := c.Param("page_size") - if pageSize == "" { - pageSizeInt = 0 - } else { - pageSizeInt, err = strconv.Atoi(pageSize) - if err != nil { - common.ErrorWithCode(c, common.CodeBadRequest, "Page size must be an integer") - return - } - } - - var req ListUsersRequest var users []map[string]interface{} - if err = c.ShouldBindJSON(&req); err != nil { - users, err = h.service.ListUsers(pageInt, pageSizeInt) - if err != nil { - common.ErrorWithCode(c, common.CodeServerError, err.Error()) - return - } + switch common.GetRAGFlowType() { + case common.OpenSourceVersion: - common.SuccessWithData(c, users, "Get all users") - } else { - users, err = h.service.ListUsersEnterprise(pageInt, pageSizeInt, req.UserStatus, req.OrderBy, req.Plan, req.Top, req.Days, req.Quota) + users, err = h.service.ListUsers(pageInt, pageSizeInt, name, status, sort, orderBy) if err != nil { common.ErrorWithCode(c, common.CodeServerError, err.Error()) return } common.SuccessWithData(c, users, "List users") + case common.EnterpriseEdition: + users, err = h.service.ListUsersEE(pageInt, pageSizeInt, name, status, role, sort, orderBy, plan, topInt, daysInt, quotaInt) + if err != nil { + common.ErrorWithCode(c, common.CodeServerError, err.Error()) + return + } + default: + common.ErrorWithCode(c, common.CodeBadRequest, "Invalid RAGFlow type") + return } + common.SuccessWithData(c, users, "List users") + return } // CreateUserHTTPRequest create user request @@ -730,8 +745,8 @@ func (h *Handler) ListEnvironments(c *gin.Context) { // GetVersion handle get version func (h *Handler) GetVersion(c *gin.Context) { - version := h.service.GetVersion() - common.SuccessWithData(c, gin.H{"version": version}, "") + version, versionType := h.service.GetVersion() + common.SuccessWithData(c, gin.H{"version": version, "version_type": versionType}, "") } // GetFingerprint handle get system fingerprint diff --git a/internal/admin/enterprise_handler.go b/internal/admin/handler_ee.go similarity index 100% rename from internal/admin/enterprise_handler.go rename to internal/admin/handler_ee.go diff --git a/internal/admin/service.go b/internal/admin/service.go index ce7f3194ff..6ee30fc6eb 100644 --- a/internal/admin/service.go +++ b/internal/admin/service.go @@ -140,8 +140,8 @@ func generateRandomHex(n int) string { } // ListUsers list all users -func (s *Service) ListUsers(page, pageSize int) ([]map[string]interface{}, error) { - users, _, err := s.userDAO.List(page*pageSize, pageSize) +func (s *Service) ListUsers(pageIndex, pageSize int, name, status, sort, orderBy string) ([]map[string]interface{}, error) { + users, _, err := s.userDAO.List(pageIndex*pageSize, pageSize, name, status, sort, orderBy) if err != nil { return nil, err } @@ -1544,8 +1544,8 @@ func (s *Service) ListEnvironments() ([]map[string]interface{}, error) { // Version methods // GetVersion get RAGFlow version -func (s *Service) GetVersion() string { - return utility.GetRAGFlowVersion() +func (s *Service) GetVersion() (string, string) { + return common.GetRAGFlowVersion(), common.GetRAGFlowType() } // Sandbox methods diff --git a/internal/admin/enterprise_service.go b/internal/admin/service_ee.go similarity index 98% rename from internal/admin/enterprise_service.go rename to internal/admin/service_ee.go index 3697485996..37f73f29c0 100644 --- a/internal/admin/enterprise_service.go +++ b/internal/admin/service_ee.go @@ -788,26 +788,19 @@ func (s *Service) ShowUsersActivity(days, windows *int) (map[string]interface{}, return result, nil } -func (s *Service) ListUsersEnterprise(pageIndex, pageSize int, status, 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, quota int) ([]map[string]interface{}, error) { item := map[string]interface{}{} - if status != nil { - item["status"] = *status - } - if orderBy != nil { - item["order_by"] = *orderBy - } - if plan != nil { - item["plan"] = *plan - } - if top != nil { - item["top"] = *top - } - if days != nil { - item["days"] = *days - } - if quota != nil { - item["quota"] = *quota - } + item["pageIndex"] = pageIndex + item["pageSize"] = pageSize + item["name"] = name + item["status"] = status + item["role"] = role + item["sort"] = sort + item["order_by"] = orderBy + item["plan"] = plan + item["top"] = top + item["days"] = days + item["quota"] = quota var result []map[string]interface{} result = append(result, item) diff --git a/internal/common/response.go b/internal/common/http.go similarity index 81% rename from internal/common/response.go rename to internal/common/http.go index e7adffe74c..e3827b5e4d 100644 --- a/internal/common/response.go +++ b/internal/common/http.go @@ -17,7 +17,9 @@ package common import ( + "fmt" "net/http" + "strconv" "github.com/gin-gonic/gin" ) @@ -91,3 +93,21 @@ func ResponseWithHttpCodeData(c *gin.Context, httpCode int, code ErrorCode, data Message: message, }) } + +func ParseRequestIntPositive(c *gin.Context, parameter, parameterName string, defaultValue int) (int, error) { + var parameterInt int + var err error + if parameter == "" { + parameterInt = defaultValue + } else { + parameterInt, err = strconv.Atoi(parameter) + if err != nil { + return defaultValue, fmt.Errorf("%w: %s must be an integer", err, parameterName) + } + } + + if parameterInt < 0 { + return defaultValue, fmt.Errorf("%w: %s must be a positive integer or zero", err, parameterName) + } + return parameterInt, nil +} diff --git a/internal/utility/version.go b/internal/common/version.go similarity index 87% rename from internal/utility/version.go rename to internal/common/version.go index 6293763a41..12965db071 100644 --- a/internal/utility/version.go +++ b/internal/common/version.go @@ -13,7 +13,7 @@ // limitations under the License. // -package utility +package common import ( "os" @@ -24,21 +24,21 @@ import ( ) var ( - ragflowVersionInfo = "unknown" - versionOnce sync.Once + versionInfo = "unknown" + versionOnce sync.Once ) // GetRAGFlowVersion gets the RAGFlow version information // It reads from VERSION file or falls back to git describe command func GetRAGFlowVersion() string { versionOnce.Do(func() { - ragflowVersionInfo = getRAGFlowVersionInternal() + versionInfo = getVersionInternal() }) - return ragflowVersionInfo + return versionInfo } -// getRAGFlowVersionInternal internal function to get version -func getRAGFlowVersionInternal() string { +// getVersionInternal internal function to get version +func getVersionInternal() string { // Get the path to VERSION file // Assuming this file is in internal/utility, VERSION is in project root exePath, err := os.Executable() diff --git a/internal/common/version_ee.go b/internal/common/version_ee.go new file mode 100644 index 0000000000..22dd66f6f9 --- /dev/null +++ b/internal/common/version_ee.go @@ -0,0 +1,23 @@ +// Copyright 2026 The InfiniFlow Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package common + +var OpenSourceVersion = "open source" +var EnterpriseEdition = "enterprise edition" + +func GetRAGFlowType() string { + return OpenSourceVersion +} diff --git a/internal/utility/version_test.go b/internal/common/version_test.go similarity index 98% rename from internal/utility/version_test.go rename to internal/common/version_test.go index 7c3384274a..4eddc74b69 100644 --- a/internal/utility/version_test.go +++ b/internal/common/version_test.go @@ -14,7 +14,7 @@ // limitations under the License. // -package utility +package common import ( "fmt" diff --git a/internal/dao/user.go b/internal/dao/user.go index 09e28ddc95..6ecbabc1ea 100644 --- a/internal/dao/user.go +++ b/internal/dao/user.go @@ -97,7 +97,7 @@ func (dao *UserDAO) UpdateAccessToken(user *entity.User, token string) error { } // List list users (only active users with status != "0") -func (dao *UserDAO) List(offset, limit int) ([]*entity.User, int64, error) { +func (dao *UserDAO) List(offset, limit int, name, status, sort, orderBy string) ([]*entity.User, int64, error) { var users []*entity.User var total int64 diff --git a/internal/handler/user.go b/internal/handler/user.go index d339836c49..6c82e65b95 100644 --- a/internal/handler/user.go +++ b/internal/handler/user.go @@ -214,41 +214,6 @@ func (h *UserHandler) GetUserByID(c *gin.Context) { common.SuccessWithData(c, user, "success") } -// ListUsers user list -// @Summary User List -// @Description Get paginated user list -// @Tags users -// @Accept json -// @Produce json -// @Param page query int false "page number" default(1) -// @Param page_size query int false "items per page" default(10) -// @Success 200 {object} map[string]interface{} -// @Router /api/v1/users [get] -func (h *UserHandler) ListUsers(c *gin.Context) { - page, _ := strconv.Atoi(c.DefaultQuery("page", "1")) - pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "10")) - - if page < 1 { - page = 1 - } - if pageSize < 1 || pageSize > 100 { - pageSize = 10 - } - - users, total, code, err := h.userService.ListUsers(page, pageSize) - if err != nil { - common.ResponseWithCodeData(c, code, false, err.Error()) - return - } - - common.SuccessWithData(c, gin.H{ - "items": users, - "total": total, - "page": page, - "page_size": pageSize, - }, "success") -} - // Logout user logout // @Summary User Logout // @Description Logout user and invalidate access token diff --git a/internal/service/admin_client.go b/internal/service/admin_client.go index 05c3be0057..bb5426d5ef 100644 --- a/internal/service/admin_client.go +++ b/internal/service/admin_client.go @@ -51,7 +51,7 @@ func NewAdminClient(logger *zap.Logger, serverType common.ServerType, serverName serverName: serverName, host: host, port: port, - version: utility.GetRAGFlowVersion(), + version: common.GetRAGFlowVersion(), lastSuccess: false, attemptCount: 0, } diff --git a/internal/service/system.go b/internal/service/system.go index 729971d73b..c89909ef88 100644 --- a/internal/service/system.go +++ b/internal/service/system.go @@ -30,7 +30,6 @@ import ( "ragflow/internal/engine" "ragflow/internal/server" "ragflow/internal/storage" - "ragflow/internal/utility" ) // SystemService system service @@ -67,6 +66,7 @@ func (s *SystemService) GetConfig() (*ConfigResponse, error) { // VersionResponse version response type VersionResponse struct { Version string `json:"version"` + Type string `json:"type"` } type HealthzMeta struct { @@ -86,9 +86,11 @@ type HealthzResponse struct { // GetVersion get RAGFlow version func (s *SystemService) GetVersion() (*VersionResponse, error) { - version := utility.GetRAGFlowVersion() + version := common.GetRAGFlowVersion() + versionType := common.GetRAGFlowType() return &VersionResponse{ Version: version, + Type: versionType, }, nil } diff --git a/internal/service/user.go b/internal/service/user.go index 4898ab520d..42db4af8dd 100644 --- a/internal/service/user.go +++ b/internal/service/user.go @@ -442,33 +442,6 @@ func (s *UserService) GetUserByID(id uint) (*UserResponse, common.ErrorCode, err }, common.CodeSuccess, nil } -// ListUsers list users -func (s *UserService) ListUsers(page, pageSize int) ([]*UserResponse, int64, common.ErrorCode, error) { - offset := (page - 1) * pageSize - users, total, err := s.userDAO.List(offset, pageSize) - if err != nil { - return nil, 0, common.CodeServerError, err - } - - responses := make([]*UserResponse, len(users)) - for i, user := range users { - responses[i] = &UserResponse{ - ID: user.ID, - Email: user.Email, - Nickname: user.Nickname, - Status: user.Status, - CreatedAt: func() string { - if user.CreateTime != nil { - return time.Unix(*user.CreateTime, 0).Format("2006-01-02 15:04:05") - } - return "" - }(), - } - } - - return responses, total, common.CodeSuccess, nil -} - // VerifyPassword verify password // Supports both werkzeug pbkdf2 format (pbkdf2:sha256:iterations$salt$hash) and scrypt format func (s *UserService) VerifyPassword(hashedPassword, password string) bool {