diff --git a/internal/admin/enterprise_handler.go b/internal/admin/enterprise_handler.go index 6bd4fb2905..c325599c69 100644 --- a/internal/admin/enterprise_handler.go +++ b/internal/admin/enterprise_handler.go @@ -217,6 +217,17 @@ func (h *Handler) ListResources(c *gin.Context) { common.SuccessWithData(c, resources, "") } +// ListRolesWithPermission handle list roles with permission +func (h *Handler) ListRolesWithPermission(c *gin.Context) { + roles, err := h.service.ListRolesWithPermission() + if err != nil { + common.ErrorWithCode(c, common.CodeServerError, err.Error()) + return + } + + common.SuccessWithData(c, roles, "") +} + func (h *Handler) ShowRoleDefaultModels(c *gin.Context) { roleName := c.Param("role_name") if roleName == "" { @@ -1275,10 +1286,6 @@ func (h *Handler) ListUserDefaultModels(c *gin.Context) { func (h *Handler) ShowUsersSummary(c *gin.Context) { usersSummary, err := h.service.ShowUsersSummary() if err != nil { - if errors.Is(err, common.ErrUserNotFound) { - common.ErrorWithCode(c, common.CodeNotFound, "User not found") - return - } common.ErrorWithCode(c, common.CodeServerError, err.Error()) return } @@ -1301,10 +1308,6 @@ func (h *Handler) ShowUsersActivity(c *gin.Context) { } usersActivity, err := h.service.ShowUsersActivity(req.Days, req.Window) if err != nil { - if errors.Is(err, common.ErrUserNotFound) { - common.ErrorWithCode(c, common.CodeNotFound, "User not found") - return - } common.ErrorWithCode(c, common.CodeServerError, err.Error()) return } @@ -1349,10 +1352,6 @@ func (h *Handler) ListUsersReports(c *gin.Context) { usersReports, err := h.service.ListUsersReports(pageIndex, pageSize, req.Status, req.Plan, req.Days) if err != nil { - if errors.Is(err, common.ErrUserNotFound) { - common.ErrorWithCode(c, common.CodeNotFound, "User not found") - return - } common.ErrorWithCode(c, common.CodeServerError, err.Error()) return } @@ -1393,10 +1392,6 @@ func (h *Handler) ListUsersStorage(c *gin.Context) { usersStorage, err := h.service.ListUsersStorage(pageIndex, pageSize, top) if err != nil { - if errors.Is(err, common.ErrUserNotFound) { - common.ErrorWithCode(c, common.CodeNotFound, "User not found") - return - } common.ErrorWithCode(c, common.CodeServerError, err.Error()) return } @@ -1437,10 +1432,6 @@ func (h *Handler) ListUsersDocuments(c *gin.Context) { usersDocuments, err := h.service.ListUsersDocuments(pageIndex, pageSize, top) if err != nil { - if errors.Is(err, common.ErrUserNotFound) { - common.ErrorWithCode(c, common.CodeNotFound, "User not found") - return - } common.ErrorWithCode(c, common.CodeServerError, err.Error()) return } @@ -1481,10 +1472,6 @@ func (h *Handler) ListUsersIndex(c *gin.Context) { usersIndex, err := h.service.ListUsersIndex(pageIndex, pageSize, top) if err != nil { - if errors.Is(err, common.ErrUserNotFound) { - common.ErrorWithCode(c, common.CodeNotFound, "User not found") - return - } common.ErrorWithCode(c, common.CodeServerError, err.Error()) return } @@ -1537,10 +1524,6 @@ func (h *Handler) ListUsersQuota(c *gin.Context) { usersQuota, err := h.service.ListUsersQuota(pageIndex, pageSize, top, request.QuotaThreshold, request.Plan, request.Days) if err != nil { - if errors.Is(err, common.ErrUserNotFound) { - common.ErrorWithCode(c, common.CodeNotFound, "User not found") - return - } common.ErrorWithCode(c, common.CodeServerError, err.Error()) return } @@ -1552,10 +1535,6 @@ func (h *Handler) ListUsersQuota(c *gin.Context) { func (h *Handler) ShowUsersPlanSummary(c *gin.Context) { usersPlanSummary, err := h.service.ShowUsersPlanSummary() if err != nil { - if errors.Is(err, common.ErrUserNotFound) { - common.ErrorWithCode(c, common.CodeNotFound, "User not found") - return - } common.ErrorWithCode(c, common.CodeServerError, err.Error()) return } @@ -1577,10 +1556,6 @@ func (h *Handler) ShowUsersPlan(c *gin.Context) { } usersPlanQuota, err := h.service.ShowUsersPlanQuota(quota) if err != nil { - if errors.Is(err, common.ErrUserNotFound) { - common.ErrorWithCode(c, common.CodeNotFound, "User not found") - return - } common.ErrorWithCode(c, common.CodeServerError, err.Error()) return } @@ -1592,10 +1567,6 @@ func (h *Handler) ShowUsersPlan(c *gin.Context) { func (h *Handler) ShowUsersQuotaSummary(c *gin.Context) { usersQuotaSummary, err := h.service.ShowUsersQuotaSummary() if err != nil { - if errors.Is(err, common.ErrUserNotFound) { - common.ErrorWithCode(c, common.CodeNotFound, "User not found") - return - } common.ErrorWithCode(c, common.CodeServerError, err.Error()) return } @@ -1607,10 +1578,6 @@ func (h *Handler) ShowUsersQuotaSummary(c *gin.Context) { func (h *Handler) ShowIngestionTasksSummary(c *gin.Context) { ingestionTasksSummary, err := h.service.ShowIngestionTasksSummary() if err != nil { - if errors.Is(err, common.ErrUserNotFound) { - common.ErrorWithCode(c, common.CodeNotFound, "User not found") - return - } common.ErrorWithCode(c, common.CodeServerError, err.Error()) return } @@ -1622,10 +1589,6 @@ func (h *Handler) ShowIngestionTasksSummary(c *gin.Context) { func (h *Handler) ShowDataSummary(c *gin.Context) { dataSummary, err := h.service.ShowDataSummary() if err != nil { - if errors.Is(err, common.ErrUserNotFound) { - common.ErrorWithCode(c, common.CodeNotFound, "User not found") - return - } common.ErrorWithCode(c, common.CodeServerError, err.Error()) return } @@ -1637,10 +1600,6 @@ func (h *Handler) ShowDataSummary(c *gin.Context) { func (h *Handler) ShowDataOrphan(c *gin.Context) { dataOrphan, err := h.service.ShowDataOrphan() if err != nil { - if errors.Is(err, common.ErrUserNotFound) { - common.ErrorWithCode(c, common.CodeNotFound, "User not found") - return - } common.ErrorWithCode(c, common.CodeServerError, err.Error()) return } @@ -1652,10 +1611,6 @@ func (h *Handler) ShowDataOrphan(c *gin.Context) { func (h *Handler) ShowDataStorage(c *gin.Context) { dataStorage, err := h.service.ShowDataStorage() if err != nil { - if errors.Is(err, common.ErrUserNotFound) { - common.ErrorWithCode(c, common.CodeNotFound, "User not found") - return - } common.ErrorWithCode(c, common.CodeServerError, err.Error()) return } @@ -1667,10 +1622,6 @@ func (h *Handler) ShowDataStorage(c *gin.Context) { func (h *Handler) ShowDataIndex(c *gin.Context) { dataIndex, err := h.service.ShowDataIndex() if err != nil { - if errors.Is(err, common.ErrUserNotFound) { - common.ErrorWithCode(c, common.CodeNotFound, "User not found") - return - } common.ErrorWithCode(c, common.CodeServerError, err.Error()) return } @@ -1692,10 +1643,6 @@ func (h *Handler) PurgeOrphanData(c *gin.Context) { } result, err := h.service.PurgeOrphanData(request.Preview) if err != nil { - if errors.Is(err, common.ErrUserNotFound) { - common.ErrorWithCode(c, common.CodeNotFound, "User not found") - return - } common.ErrorWithCode(c, common.CodeServerError, err.Error()) return } @@ -1830,3 +1777,215 @@ func (h *Handler) ListUserAPIKeys(c *gin.Context) { common.SuccessWithData(c, result, "API keys listed successfully") } + +// DownloadSensitiveWords handle download sensitive words +func (h *Handler) DownloadSensitiveWords(c *gin.Context) { + result, err := h.service.DownloadSensitiveWords() + if err != nil { + common.ErrorWithCode(c, common.CodeServerError, err.Error()) + return + } + + common.SuccessWithData(c, result, "Sensitive words downloaded successfully") +} + +// UploadSensitiveWords handle upload sensitive words +func (h *Handler) UploadSensitiveWords(c *gin.Context) { + form, err := c.MultipartForm() + if err != nil || form == nil || len(form.File["file"]) == 0 { + common.ResponseWithCodeData(c, common.CodeArgumentError, nil, "No file part!") + return + } + files := form.File["file"] + for _, fh := range files { + if fh == nil || fh.Filename == "" { + common.ResponseWithCodeData(c, common.CodeArgumentError, nil, "No file or filename is empty") + return + } + } + if len(files) != 1 { + common.ResponseWithCodeData(c, common.CodeArgumentError, nil, "Only one file is allowed") + return + } + file := files[0] + result, err := h.service.UploadSensitiveWords(file) + if err != nil { + common.ErrorWithCode(c, common.CodeServerError, err.Error()) + return + } + + common.SuccessWithData(c, result, "Sensitive words uploaded successfully") +} + +type BindVerificationEmailRequest struct { + Email string `json:"email"` + Host string `json:"host"` + Port int `json:"port"` + Username string `json:"username"` + Password string `json:"password"` + UseTLS bool `json:"use_tls"` + UseSSL bool `json:"use_ssl"` +} + +// BindVerificationEmail handle bind verification email +func (h *Handler) BindVerificationEmail(c *gin.Context) { + var request BindVerificationEmailRequest + if err := c.ShouldBindJSON(&request); err != nil { + println("JSON bind error: %v (type: %T)", err, err) + common.ErrorWithCode(c, common.CodeBadRequest, err.Error()) + return + } + if request.Email == "" || request.Host == "" || request.Username == "" || request.Password == "" { + common.ErrorWithCode(c, common.CodeBadRequest, "Email, host, username, and password are required") + return + } + + result, err := h.service.BindVerificationEmail(request.Email, request.Host, request.Port, request.Username, request.Password, request.UseTLS, request.UseSSL) + if err != nil { + common.ErrorWithCode(c, common.CodeServerError, err.Error()) + return + } + + common.SuccessWithData(c, result, "Verification email bound successfully") +} + +// ShowVerificationEmail handle show verification email +func (h *Handler) ShowVerificationEmail(c *gin.Context) { + result, err := h.service.ShowVerificationEmail() + if err != nil { + common.ErrorWithCode(c, common.CodeServerError, err.Error()) + return + } + + common.SuccessWithData(c, result, "Verification email shown successfully") +} + +// ShowWhiteList handle show white list +func (h *Handler) ShowWhiteList(c *gin.Context) { + result, err := h.service.ShowWhiteList() + if err != nil { + common.ErrorWithCode(c, common.CodeServerError, err.Error()) + return + } + + common.SuccessWithData(c, result, "White list shown successfully") +} + +type AddWhiteListRequest struct { + Email string `json:"email"` +} + +// AddWhiteList handle add white list +func (h *Handler) AddWhiteList(c *gin.Context) { + var request AddWhiteListRequest + if err := c.ShouldBindJSON(&request); err != nil { + common.ErrorWithCode(c, common.CodeBadRequest, err.Error()) + return + } + if request.Email == "" { + common.ErrorWithCode(c, common.CodeBadRequest, "Email is required") + return + } + + result, err := h.service.AddWhiteList(request.Email) + if err != nil { + common.ErrorWithCode(c, common.CodeServerError, err.Error()) + return + } + + common.SuccessWithData(c, result, "White list added successfully") +} + +// BatchAddWhiteList handle batch add white list +func (h *Handler) BatchAddWhiteList(c *gin.Context) { + form, err := c.MultipartForm() + if err != nil || form == nil || len(form.File["file"]) == 0 { + common.ResponseWithCodeData(c, common.CodeArgumentError, nil, "No file part!") + return + } + files := form.File["file"] + for _, fh := range files { + if fh == nil || fh.Filename == "" { + common.ResponseWithCodeData(c, common.CodeArgumentError, nil, "No file or filename is empty") + return + } + } + if len(files) != 1 { + common.ResponseWithCodeData(c, common.CodeArgumentError, nil, "Only one file is allowed") + return + } + file := files[0] + result, err := h.service.BatchAddWhiteList(file) + if err != nil { + common.ErrorWithCode(c, common.CodeServerError, err.Error()) + return + } + + common.SuccessWithData(c, result, "Batch add white list successfully") +} + +// UpdateWhiteList handle update white list +func (h *Handler) UpdateWhiteList(c *gin.Context) { + id := c.Param("id") + + var request AddWhiteListRequest + if err := c.ShouldBindJSON(&request); err != nil { + common.ErrorWithCode(c, common.CodeBadRequest, err.Error()) + return + } + if request.Email == "" { + common.ErrorWithCode(c, common.CodeBadRequest, "Email is required") + return + } + + result, err := h.service.UpdateWhiteList(id, request.Email) + if err != nil { + common.ErrorWithCode(c, common.CodeServerError, err.Error()) + return + } + + common.SuccessWithData(c, result, "White list updated successfully") +} + +// DeleteWhiteList handle delete white list +func (h *Handler) DeleteWhiteList(c *gin.Context) { + idStr := c.Param("id") + id, err := strconv.Atoi(idStr) + if err != nil { + common.ErrorWithCode(c, common.CodeBadRequest, "Invalid id") + return + } + + result, err := h.service.DeleteWhiteList(id) + if err != nil { + common.ErrorWithCode(c, common.CodeServerError, err.Error()) + return + } + + common.SuccessWithData(c, result, "White list updated successfully") +} + +type BatchDeleteWhiteListRequest struct { + Ids []int `json:"ids"` +} + +// BatchDeleteWhiteList handle batch delete white list +func (h *Handler) BatchDeleteWhiteList(c *gin.Context) { + var request BatchDeleteWhiteListRequest + if err := c.ShouldBindJSON(&request); err != nil { + common.ErrorWithCode(c, common.CodeBadRequest, err.Error()) + return + } + if len(request.Ids) == 0 { + common.ErrorWithCode(c, common.CodeBadRequest, "Ids are required") + return + } + + result, err := h.service.BatchDeleteWhiteList(request.Ids) + if err != nil { + common.ErrorWithCode(c, common.CodeServerError, err.Error()) + return + } + + common.SuccessWithData(c, result, "Batch delete white list successfully") +} diff --git a/internal/admin/enterprise_service.go b/internal/admin/enterprise_service.go index 8b16427270..3697485996 100644 --- a/internal/admin/enterprise_service.go +++ b/internal/admin/enterprise_service.go @@ -19,6 +19,7 @@ package admin import ( "errors" "fmt" + "mime/multipart" "ragflow/internal/common" "ragflow/internal/dao" "ragflow/internal/entity" @@ -132,6 +133,16 @@ func (s *Service) ListResources() (map[string]interface{}, error) { return result, nil } +// ListRolesWithPermission list roles with permission +func (s *Service) ListRolesWithPermission() ([]map[string]interface{}, error) { + return []map[string]interface{}{ + { + "command": "list_roles_with_permission", + "error": "'list roles with permission' is not supported", + }, + }, nil +} + func (s *Service) ShowRoleDefaultModels(roleName string) ([]map[string]interface{}, error) { return []map[string]interface{}{ { @@ -1173,3 +1184,113 @@ func (s *Service) RemoveIngestionTasksByCondition(tasks []string, email, status func CheckLicense() (common.ErrorCode, string) { return common.CodeLicenseValid, "" } + +// DownloadSensitiveWords download sensitive words +func (s *Service) DownloadSensitiveWords() ([]map[string]interface{}, error) { + result := []map[string]interface{}{ + { + "command": "download_sensitive_words", + "error": "'Download sensitive words' is not supported", + }, + } + return result, nil +} + +// UploadSensitiveWords upload sensitive words +func (s *Service) UploadSensitiveWords(file *multipart.FileHeader) ([]map[string]interface{}, error) { + result := []map[string]interface{}{ + { + "command": "upload_sensitive_words", + "filename": file.Filename, + "error": "'Upload sensitive words' is not supported", + }, + } + return result, nil +} + +// BindVerificationEmail bind verification email +func (s *Service) BindVerificationEmail(email, host string, port int, username, password string, useTLS, useSSL bool) (map[string]interface{}, error) { + result := map[string]interface{}{ + "command": "bind_verification_email", + "email": email, + "host": host, + "port": port, + "username": username, + "password": password, + "use_tls": useTLS, + "use_ssl": useSSL, + "error": "'Bind verification email' is not supported", + } + return result, nil +} + +// ShowVerificationEmail show verification email +func (s *Service) ShowVerificationEmail() (map[string]interface{}, error) { + result := map[string]interface{}{ + "command": "show_verification_email", + "error": "'Show verification email' is not supported", + } + return result, nil +} + +// ShowWhiteList show white list +func (s *Service) ShowWhiteList() ([]map[string]interface{}, error) { + result := []map[string]interface{}{ + { + "command": "show_white_list", + "error": "'Show white list' is not supported", + }, + } + return result, nil +} + +// AddWhiteList add white list +func (s *Service) AddWhiteList(email string) (map[string]interface{}, error) { + result := map[string]interface{}{ + "command": "add_white_list", + "email": email, + "error": "'Add white list' is not supported", + } + return result, nil +} + +// BatchAddWhiteList batch add white list +func (s *Service) BatchAddWhiteList(file *multipart.FileHeader) (map[string]interface{}, error) { + result := map[string]interface{}{ + "command": "batch_add_white_list", + "filename": file.Filename, + "error": "'Batch add white list' is not supported", + } + return result, nil +} + +// UpdateWhiteList update white list +func (s *Service) UpdateWhiteList(id, email string) (map[string]interface{}, error) { + result := map[string]interface{}{ + "command": "update_white_list", + "id": id, + "email": email, + "error": "'Update white list' is not supported", + } + return result, nil +} + +// DeleteWhiteList delete white list +func (s *Service) DeleteWhiteList(id int) (map[string]interface{}, error) { + result := map[string]interface{}{ + "command": "delete_white_list", + "id": id, + "error": "'Delete white list' is not supported", + } + return result, nil +} + +// BatchDeleteWhiteList batch delete white list +func (s *Service) BatchDeleteWhiteList(ids []int) (map[string]interface{}, error) { + result := map[string]interface{}{ + "command": "batch_delete_white_list", + "ids": ids, + "error": "'Batch delete white list' is not supported", + } + return result, nil +} diff --git a/internal/admin/router.go b/internal/admin/router.go index 1576a4ee38..48293553a8 100644 --- a/internal/admin/router.go +++ b/internal/admin/router.go @@ -176,6 +176,7 @@ func (r *Router) Setup(engine *gin.Engine) { protected.POST("/roles/:role_name/permission", r.handler.GrantRolePermission) protected.DELETE("/roles/:role_name/permission", r.handler.RevokeRolePermission) protected.GET("/roles/resource", r.handler.ListResources) + protected.GET("/roles/permission", r.handler.ListRolesWithPermission) protected.GET("/roles/:role_name/default-models", r.handler.ShowRoleDefaultModels) protected.PATCH("/roles/:role_name/default-models", r.handler.SetRoleDefaultModel) protected.DELETE("/roles/:role_name/default-models", r.handler.ResetRoleDefaultModel) @@ -208,6 +209,27 @@ func (r *Router) Setup(engine *gin.Engine) { protected.GET("/all-models", r.handler.ListAllModels) protected.GET("/all-models/:model_name", r.handler.ShowModel) + // Sensitive words, EE + protected.GET("/sensitive-words", r.handler.DownloadSensitiveWords) + protected.POST("/sensitive-words", r.handler.UploadSensitiveWords) + + // Verification email, EE + protected.POST("/email/verification", r.handler.BindVerificationEmail) + protected.GET("/email/verification", r.handler.ShowVerificationEmail) + + // White list, EE + protected.GET("/white-list", r.handler.ShowWhiteList) + protected.POST("/white-list", r.handler.AddWhiteList) + protected.POST("/white-list/batch", r.handler.BatchAddWhiteList) + protected.PUT("/white-list/:id", r.handler.UpdateWhiteList) + protected.DELETE("/white-list/:id", r.handler.DeleteWhiteList) + protected.DELETE("/white-list/batch", r.handler.BatchDeleteWhiteList) + + // Ingestion tasks + protected.DELETE("/ingestion/tasks", r.handler.RemoveIngestionTasks) + protected.PUT("/ingestion/tasks", r.handler.StopIngestionTasks) + protected.GET("/ingestion/tasks", r.handler.ListIngestionTasks) + // License protected.GET("/system/fingerprint", r.handler.GetSystemFingerprint) protected.POST("/system/license", r.handler.SetSystemLicense) @@ -220,11 +242,6 @@ func (r *Router) Setup(engine *gin.Engine) { protected.POST("/license", r.handler.SetLicense) protected.POST("/license/config", r.handler.UpdateLicenseConfig) protected.GET("/license", r.handler.ShowLicense) - - // Ingestion tasks - protected.DELETE("/ingestion/tasks", r.handler.RemoveIngestionTasks) - protected.PUT("/ingestion/tasks", r.handler.StopIngestionTasks) - protected.GET("/ingestion/tasks", r.handler.ListIngestionTasks) } }