diff --git a/docs/changelog/index.md b/docs/changelog/index.md index db2741f7..4def56f5 100644 --- a/docs/changelog/index.md +++ b/docs/changelog/index.md @@ -26,7 +26,7 @@ sidebar: false ### 变更 -- 提取并新增 `common/response` 通用响应子包,替换 `controller/response.go` 中的响应细节,重构所有中间件中硬编码的 `c.JSON` 响应,统一 API 响应格式并隔离 Gin 依赖。 +- 提取并新增 `common/response` 通用响应子包与 `controller/bind` 参数解析绑定子包,重构所有控制器与中间件中硬编码的 `c.JSON` 及参数绑定逻辑,彻底隔离 Gin 依赖并避免变量遮蔽冲突。 - 将 `usage.md` 改名为 `proxy-config.md`(新建反代配置),重新梳理大纲结构,专注于如何从导入/申请证书开始,一步步新增并发布代理路由规则,并同步更新全部导航与文档引用链接 - WAF 白名单调整为准入名单语义:存在白名单规则时,未命中白名单的请求会被拦截 diff --git a/docs/plan/20260605-move-response-to-common.md b/docs/plan/20260605-move-response-to-common.md deleted file mode 100644 index 62c54ef3..00000000 --- a/docs/plan/20260605-move-response-to-common.md +++ /dev/null @@ -1,53 +0,0 @@ -# 提取公共 Response 包以支持 Middleware 统一响应实现计划 - ---- - -## 1. 目标与背景 (Goal & Context) -* **需求背景**: - 原本 `response.go` 放在 `controller` 目录下。由于 `middleware` 处于 `controller` 上游,并且和 `controller` 跨包,`middleware` 无法直接调用 `controller` 的响应逻辑。这导致 `middleware` 中存在许多手写的、格式硬编码的 `c.JSON` 调用。 - 如果直接将 `response.go` 放入已有的 `common` 根包,会引入 `github.com/gin-gonic/gin` 依赖,导致依赖 `common` 的底层 `service` 和 `model` 也受到 `gin` 框架的依赖污染。 -* **开发范围 (Scope)**: - * 在 `openflare_server/common/response` 下新建 `response.go` 子包(`package response`),存放通用的 HTTP 响应逻辑。 - * 将 `controller/response.go` 中的响应逻辑移植到 `common/response/response.go`。 - * 在 `controller/response.go` 中保留参数解析逻辑,并作为代理调用 `common/response` 中的方法,从而实现对 controller 内 140+ 处现有调用的**零改动**。 - * 修改 `middleware` 包下的所有 `c.JSON` 手写响应,统一采用 `common/response` 的方法。 - -## 2. 设计与决策 (Design & Decisions) -* **核心对象/数据模型**:无需改动任何数据库或数据模型。 -* **API 与鉴权设计**:不改变任何公开 API 接口路由与现有的成功/失败响应 JSON 格式。 -* **设计决策权衡**: - * **方案 A:直接把 response.go 放入 common 根包** - * 缺点:导致原本不应该感知 Web 传输协议的 `service`、`model`、`job` 包间接依赖了 `github.com/gin-gonic/gin` 框架。 - * **方案 B:在 common 下建子包 `common/response`** - * 优点:满足 `common` 归类的直觉,又保持了包的物理依赖隔离。业务底层不受 `gin` 污染,而 `controller` 和 `middleware` 这类传输层可引入该包进行代码复用。**(采用此方案)** - -## 3. 具体修改文件清单 (Proposed Changes) - -### 后端 Server -* #### [NEW] [response.go](file:///Users/ryan/DEV/Go/OpenFlare/openflare_server/common/response/response.go) - * 职责:通用的 Gin 响应工具包,包括 `RespondSuccess`、`RespondSuccessWithExtras`、`RespondSuccessMessage`、`RespondFailure`、`RespondBadRequest`、`RespondUnauthorized` 和 `RespondForbidden`。 -* #### [MODIFY] [response.go](file:///Users/ryan/DEV/Go/OpenFlare/openflare_server/controller/response.go) - * 职责:删去具体的 HTTP 响应渲染实现,以代理方式调用 `common/response` 包中导出的函数,保持 controller 包内现有调用的向后兼容;保留原有的 `decodeJSONBody`、`decodeOptionalJSONBody`、`parseIDParam`、`parseIDParamByName`、`bindJSON` 参数绑定解析逻辑。 -* #### [MODIFY] [agent-auth.go](file:///Users/ryan/DEV/Go/OpenFlare/openflare_server/middleware/agent-auth.go) - * 职责:替换 `c.JSON(http.StatusUnauthorized, ...)` 为使用 `response.RespondUnauthorized(...)` 渲染统一响应。 -* #### [MODIFY] [auth.go](file:///Users/ryan/DEV/Go/OpenFlare/openflare_server/middleware/auth.go) - * 职责:替换 `c.JSON` 相关的未授权和失败响应为使用 `response` 包方法。 -* #### [MODIFY] [jwt.go](file:///Users/ryan/DEV/Go/OpenFlare/openflare_server/middleware/jwt.go) - * 职责:替换 JWT 未授权的回调响应为使用 `response` 统一格式。 -* #### [MODIFY] [relay-auth.go](file:///Users/ryan/DEV/Go/OpenFlare/openflare_server/middleware/relay-auth.go) - * 职责:替换未授权和 StatusForbidden 响应为使用 `response` 方法。 -* #### [MODIFY] [tunnel-auth.go](file:///Users/ryan/DEV/Go/OpenFlare/openflare_server/middleware/tunnel-auth.go) - * 职责:替换未授权和 StatusForbidden 响应为使用 `response` 方法。 - ---- - -## 4. 验证计划 (Verification Plan) - -### 自动化单元测试 -* 运行项目已有测试验证重构是否影响 API 连通性与响应结构: - ```bash - go test -v ./router/... - ``` - ```bash - go test -v ./service/... - ``` diff --git a/openflare_server/controller/access_log.go b/openflare_server/controller/access_log.go index f2fe875e..9338eb24 100644 --- a/openflare_server/controller/access_log.go +++ b/openflare_server/controller/access_log.go @@ -1,6 +1,8 @@ package controller import ( + "openflare/common/response" + "openflare/controller/bind" "openflare/service" "strconv" @@ -25,10 +27,10 @@ import ( func GetAccessLogs(c *gin.Context) { logs, err := service.ListAccessLogs(readAccessLogQuery(c)) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, logs) + response.RespondSuccess(c, logs) } // GetFoldedAccessLogs godoc @@ -52,10 +54,10 @@ func GetFoldedAccessLogs(c *gin.Context) { query.FoldMinutes = readQueryInt(c, "fold_minutes") logs, err := service.ListFoldedAccessLogs(query) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, logs) + response.RespondSuccess(c, logs) } // GetFoldedAccessLogIPs godoc @@ -89,10 +91,10 @@ func GetFoldedAccessLogIPs(c *gin.Context) { SortOrder: c.Query("sort_order"), }) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, result) + response.RespondSuccess(c, result) } // GetAccessLogIPSummaries godoc @@ -120,10 +122,10 @@ func GetAccessLogIPSummaries(c *gin.Context) { SortOrder: c.Query("sort_order"), }) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, result) + response.RespondSuccess(c, result) } // GetAccessLogIPTrend godoc @@ -147,10 +149,10 @@ func GetAccessLogIPTrend(c *gin.Context) { BucketMinutes: readQueryInt(c, "bucket_minutes"), }) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, result) + response.RespondSuccess(c, result) } // CleanupAccessLogs godoc @@ -163,15 +165,15 @@ func GetAccessLogIPTrend(c *gin.Context) { // @Router /api/access-logs/cleanup [post] func CleanupAccessLogs(c *gin.Context) { var input service.AccessLogCleanupInput - if !bindJSON(c, &input) { + if !bind.JSON(c, &input) { return } result, err := service.CleanupAccessLogs(input) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, result) + response.RespondSuccess(c, result) } func readAccessLogQuery(c *gin.Context) service.AccessLogQuery { diff --git a/openflare_server/controller/acme_account.go b/openflare_server/controller/acme_account.go index 42e73dc3..4e0dbd18 100644 --- a/openflare_server/controller/acme_account.go +++ b/openflare_server/controller/acme_account.go @@ -1,6 +1,7 @@ package controller import ( + "openflare/common/response" "openflare/model" "github.com/gin-gonic/gin" @@ -16,8 +17,8 @@ import ( func GetDefaultAcmeAccount(c *gin.Context) { account, err := model.GetDefaultAcmeAccount() if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, account) + response.RespondSuccess(c, account) } diff --git a/openflare_server/controller/agent.go b/openflare_server/controller/agent.go index 6de1c541..8862c5fa 100644 --- a/openflare_server/controller/agent.go +++ b/openflare_server/controller/agent.go @@ -5,6 +5,8 @@ import ( "log/slog" "net" "openflare/common" + "openflare/common/response" + "openflare/controller/bind" "openflare/model" "openflare/service" "strconv" @@ -26,7 +28,7 @@ import ( // @Router /api/agent/nodes/register [post] func AgentRegister(c *gin.Context) { var payload service.AgentNodePayload - if !bindJSON(c, &payload) { + if !bind.JSON(c, &payload) { return } payload.IP = service.ResolveReportedNodeIP(payload.IP, c.Request.RemoteAddr) @@ -41,10 +43,10 @@ func AgentRegister(c *gin.Context) { result, err = service.RegisterNodeWithDiscovery(payload) } if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, result) + response.RespondSuccess(c, result) } // AgentHeartbeat godoc @@ -59,23 +61,23 @@ func AgentRegister(c *gin.Context) { // @Router /api/agent/nodes/heartbeat [post] func AgentHeartbeat(c *gin.Context) { var payload service.AgentNodePayload - if !bindJSON(c, &payload) { + if !bind.JSON(c, &payload) { return } payload.IP = service.ResolveReportedNodeIP(payload.IP, c.Request.RemoteAddr) authNode, ok := c.Get("agent_node") if !ok { - respondUnauthorized(c, "鏃犳潈杩涜姝ゆ搷浣滐紝Agent Token 鏃犳晥") + response.RespondUnauthorized(c, "鏃犳潈杩涜姝ゆ搷浣滐紝Agent Token 鏃犳晥") return } node, err := service.HeartbeatNode(authNode.(*model.Node), payload) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccessWithExtras(c, node.Node, gin.H{ + response.RespondSuccessWithExtras(c, node.Node, gin.H{ "agent_settings": node.AgentSettings, "active_config": node.ActiveConfig, "waf_ip_groups": node.WAFIPGroups, @@ -94,15 +96,15 @@ func AgentHeartbeat(c *gin.Context) { // @Router /api/agent/waf/ip-groups/sync [post] func AgentSyncWAFIPGroups(c *gin.Context) { var input service.AgentWAFIPGroupSyncInput - if !bindJSON(c, &input) { + if !bind.JSON(c, &input) { return } result, err := service.SyncWAFIPGroupsForAgent(input) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, result) + response.RespondSuccess(c, result) } // AgentGetActiveConfig godoc @@ -115,7 +117,7 @@ func AgentSyncWAFIPGroups(c *gin.Context) { func AgentGetActiveConfig(c *gin.Context) { authNode, ok := c.Get("agent_node") if !ok { - respondUnauthorized(c, "Node object missing from context") + response.RespondUnauthorized(c, "Node object missing from context") return } node := authNode.(*model.Node) @@ -123,19 +125,19 @@ func AgentGetActiveConfig(c *gin.Context) { if node.NodeType == "tunnel_client" { config, err := service.GetFlaredTunnelConfig(node) if err != nil { - respondFailure(c, "无法生成隧道配置: "+err.Error()) + response.RespondFailure(c, "无法生成隧道配置: "+err.Error()) return } - respondSuccess(c, config) + response.RespondSuccess(c, config) return } config, err := service.GetActiveConfigForAgent() if err != nil { - respondFailure(c, "当前没有激活版本") + response.RespondFailure(c, "当前没有激活版本") return } - respondSuccess(c, config) + response.RespondSuccess(c, config) } // AgentReportApplyLog godoc @@ -150,7 +152,7 @@ func AgentGetActiveConfig(c *gin.Context) { // @Router /api/agent/apply-logs [post] func AgentReportApplyLog(c *gin.Context) { var payload service.ApplyLogPayload - if !bindJSON(c, &payload) { + if !bind.JSON(c, &payload) { return } @@ -160,10 +162,10 @@ func AgentReportApplyLog(c *gin.Context) { log, err := service.ReportApplyLog(payload) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, log) + response.RespondSuccess(c, log) } // AgentWebSocket godoc @@ -174,7 +176,7 @@ func AgentReportApplyLog(c *gin.Context) { func AgentWebSocket(c *gin.Context) { authNode, ok := c.Get("agent_node") if !ok { - respondUnauthorized(c, "无权进行此操作,Agent Token 无效") + response.RespondUnauthorized(c, "无权进行此操作,Agent Token 无效") return } node := authNode.(*model.Node) @@ -268,19 +270,19 @@ func handleAgentWSStatus(c *gin.Context, node *model.Node, message service.Agent return } payload.IP = service.ResolveReportedNodeIP(payload.IP, c.Request.RemoteAddr) - response, err := service.HeartbeatNode(freshNode, payload) + res, err := service.HeartbeatNode(freshNode, payload) if err != nil { slog.Debug("agent ws status handling failed", "node_id", node.NodeID, "error", err) return } - settingsSent := service.SendAgentWSSettings(node.NodeID, response.AgentSettings) + settingsSent := service.SendAgentWSSettings(node.NodeID, res.AgentSettings) activeConfigSent := false - if response.ActiveConfig != nil { - activeConfigSent = service.SendAgentWSActiveConfig(node.NodeID, response.ActiveConfig) + if res.ActiveConfig != nil { + activeConfigSent = service.SendAgentWSActiveConfig(node.NodeID, res.ActiveConfig) } wafIPGroupsSent := false - if len(response.WAFIPGroups) > 0 { - wafIPGroupsSent = service.SendAgentWSWAFIPGroups(node.NodeID, response.WAFIPGroups) + if len(res.WAFIPGroups) > 0 { + wafIPGroupsSent = service.SendAgentWSWAFIPGroups(node.NodeID, res.WAFIPGroups) } slog.Debug("agent ws status processed", "node_id", node.NodeID, @@ -302,10 +304,10 @@ func handleAgentWSStatus(c *gin.Context, node *model.Node, message service.Agent func GetNodes(c *gin.Context) { nodes, err := service.ListNodeViews() if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, nodes) + response.RespondSuccess(c, nodes) } // GetApplyLogs godoc @@ -323,10 +325,10 @@ func GetApplyLogs(c *gin.Context) { PageSize: readIntQueryFallback(c, "pageSize", "page_size"), }) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, logs) + response.RespondSuccess(c, logs) } // CleanupApplyLogs godoc @@ -339,15 +341,15 @@ func GetApplyLogs(c *gin.Context) { // @Router /api/apply-logs/cleanup [post] func CleanupApplyLogs(c *gin.Context) { var input service.ApplyLogCleanupInput - if !bindJSON(c, &input) { + if !bind.JSON(c, &input) { return } result, err := service.CleanupApplyLogs(input) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, result) + response.RespondSuccess(c, result) } func readIntQueryFallback(c *gin.Context, primary string, secondary string) int { diff --git a/openflare_server/controller/auth_source.go b/openflare_server/controller/auth_source.go index 53f57578..151625fa 100644 --- a/openflare_server/controller/auth_source.go +++ b/openflare_server/controller/auth_source.go @@ -5,6 +5,8 @@ import ( "fmt" "net/url" "openflare/common" + "openflare/common/response" + "openflare/controller/bind" "openflare/model" "openflare/service" "strconv" @@ -49,139 +51,139 @@ func (payload authSourcePayload) toModel() model.AuthSource { func ListAuthSources(c *gin.Context) { sources, err := model.GetAuthSources() if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, sources) + response.RespondSuccess(c, sources) } func CreateAuthSource(c *gin.Context) { var payload authSourcePayload - if err := decodeJSONBody(c.Request.Body, &payload); err != nil { - respondBadRequest(c, "无效的参数") + if err := bind.DecodeJSONBody(c.Request.Body, &payload); err != nil { + response.RespondBadRequest(c, "无效的参数") return } source := payload.toModel() if err := model.CreateAuthSource(&source); err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } source.Sanitize() - respondSuccess(c, source) + response.RespondSuccess(c, source) } func UpdateAuthSource(c *gin.Context) { id, err := parseAuthSourceID(c) if err != nil { - respondBadRequest(c, err.Error()) + response.RespondBadRequest(c, err.Error()) return } var payload authSourcePayload - if err := decodeJSONBody(c.Request.Body, &payload); err != nil { - respondBadRequest(c, "无效的参数") + if err := bind.DecodeJSONBody(c.Request.Body, &payload); err != nil { + response.RespondBadRequest(c, "无效的参数") return } source := payload.toModel() source.ID = id keepSecret := strings.TrimSpace(source.ClientSecret) == "" if err := model.UpdateAuthSource(&source, keepSecret); err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } updated, err := model.GetAuthSourceByID(id) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } updated.Sanitize() - respondSuccess(c, updated) + response.RespondSuccess(c, updated) } func DeleteAuthSource(c *gin.Context) { id, err := parseAuthSourceID(c) if err != nil { - respondBadRequest(c, err.Error()) + response.RespondBadRequest(c, err.Error()) return } if err := model.DeleteAuthSource(id); err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccessMessage(c, "") + response.RespondSuccessMessage(c, "") } func ToggleAuthSource(c *gin.Context) { id, err := parseAuthSourceID(c) if err != nil { - respondBadRequest(c, err.Error()) + response.RespondBadRequest(c, err.Error()) return } var payload authSourceTogglePayload - if err := decodeJSONBody(c.Request.Body, &payload); err != nil { - respondBadRequest(c, "无效的参数") + if err := bind.DecodeJSONBody(c.Request.Body, &payload); err != nil { + response.RespondBadRequest(c, "无效的参数") return } if err := model.ToggleAuthSource(id, payload.IsActive); err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccessMessage(c, "") + response.RespondSuccessMessage(c, "") } func OAuthAuthorize(c *gin.Context) { source, err := getAuthSourceFromRoute(c) if err != nil { - respondBadRequest(c, err.Error()) + response.RespondBadRequest(c, err.Error()) return } if !source.IsActive { - respondFailure(c, "认证源未启用") + response.RespondFailure(c, "认证源未启用") return } if err := source.Validate(); err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } state, err := service.GenerateOAuthState() if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } session := sessions.Default(c) session.Set(oauthStateSessionKey(source.ID), state) if err := session.Save(); err != nil { - respondFailure(c, "无法保存授权状态,请重试") + response.RespondFailure(c, "无法保存授权状态,请重试") return } redirectURL := oauthFrontendCallbackURL(c, source.ID) authorizeURL, err := service.BuildAuthorizeURL(c.Request.Context(), source, redirectURL, state) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, gin.H{"authorize_url": authorizeURL}) + response.RespondSuccess(c, gin.H{"authorize_url": authorizeURL}) } func OAuthCallback(c *gin.Context) { source, err := getAuthSourceFromRoute(c) if err != nil { - respondBadRequest(c, err.Error()) + response.RespondBadRequest(c, err.Error()) return } if !source.IsActive { - respondFailure(c, "认证源未启用") + response.RespondFailure(c, "认证源未启用") return } session := sessions.Default(c) expectedState, _ := session.Get(oauthStateSessionKey(source.ID)).(string) state := c.Query("state") if expectedState == "" || state == "" || state != expectedState { - respondFailure(c, "授权状态无效,请重新登录") + response.RespondFailure(c, "授权状态无效,请重新登录") return } session.Delete(oauthStateSessionKey(source.ID)) if err := session.Save(); err != nil { - respondFailure(c, "无法更新授权状态,请重试") + response.RespondFailure(c, "无法更新授权状态,请重试") return } if oauthError := c.Query("error"); oauthError != "" { @@ -189,13 +191,13 @@ func OAuthCallback(c *gin.Context) { if description == "" { description = oauthError } - respondFailure(c, description) + response.RespondFailure(c, description) return } profile, err := service.ExchangeOAuthProfile(c.Request.Context(), source, c.Query("code"), oauthFrontendCallbackURL(c, source.ID)) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } var currentUserID *int @@ -204,91 +206,91 @@ func OAuthCallback(c *gin.Context) { } result, pending, err := service.CompleteOAuthLogin(source, profile, currentUserID) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } if pending != nil { raw, err := json.Marshal(pending) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } session.Set(pendingExternalAccountSessionKey, string(raw)) if err := session.Save(); err != nil { - respondFailure(c, "无法保存待绑定账号,请重试") + response.RespondFailure(c, "无法保存待绑定账号,请重试") return } - respondSuccess(c, result) + response.RespondSuccess(c, result) return } if result.User != nil { cleanUser, err := setLoginToken(result.User) if err != nil { - respondFailure(c, "无法保存会话信息,请重试") + response.RespondFailure(c, "无法保存会话信息,请重试") return } result.User = cleanUser } - respondSuccess(c, result) + response.RespondSuccess(c, result) } func LinkExistingOAuthAccount(c *gin.Context) { session := sessions.Default(c) raw, _ := session.Get(pendingExternalAccountSessionKey).(string) if raw == "" { - respondFailure(c, "待绑定第三方账号已失效,请重新登录") + response.RespondFailure(c, "待绑定第三方账号已失效,请重新登录") return } var pending service.PendingExternalAccount if err := json.Unmarshal([]byte(raw), &pending); err != nil { - respondFailure(c, "待绑定第三方账号无效,请重新登录") + response.RespondFailure(c, "待绑定第三方账号无效,请重新登录") return } var input service.LinkExistingRequest - if err := decodeJSONBody(c.Request.Body, &input); err != nil { - respondBadRequest(c, "无效的参数") + if err := bind.DecodeJSONBody(c.Request.Body, &input); err != nil { + response.RespondBadRequest(c, "无效的参数") return } user, err := service.LinkPendingExternalAccount(&pending, input) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } session.Delete(pendingExternalAccountSessionKey) if err := session.Save(); err != nil { - respondFailure(c, "无法更新会话信息,请重试") + response.RespondFailure(c, "无法更新会话信息,请重试") return } cleanUser, err := setLoginToken(user) if err != nil { - respondFailure(c, "无法保存会话信息,请重试") + response.RespondFailure(c, "无法保存会话信息,请重试") return } - respondSuccess(c, service.OAuthCallbackResult{Status: "linked", User: cleanUser}) + response.RespondSuccess(c, service.OAuthCallbackResult{Status: "linked", User: cleanUser}) } func ListExternalAccounts(c *gin.Context) { userID := c.GetInt("id") accounts, err := model.ListExternalAccountsByUserID(userID) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, accounts) + response.RespondSuccess(c, accounts) } func DeleteExternalAccount(c *gin.Context) { rawID := strings.TrimSpace(c.Param("id")) parsedID, err := strconv.ParseUint(rawID, 10, 64) if err != nil || parsedID == 0 { - respondBadRequest(c, "绑定记录 ID 无效") + response.RespondBadRequest(c, "绑定记录 ID 无效") return } if err := model.DeleteExternalAccountForUser(uint(parsedID), c.GetInt("id")); err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccessMessage(c, "") + response.RespondSuccessMessage(c, "") } func parseAuthSourceID(c *gin.Context) (uint, error) { diff --git a/openflare_server/controller/bind/bind.go b/openflare_server/controller/bind/bind.go new file mode 100644 index 00000000..0d91dd22 --- /dev/null +++ b/openflare_server/controller/bind/bind.go @@ -0,0 +1,49 @@ +package bind + +import ( + "encoding/json" + "errors" + "io" + "strconv" + + "github.com/gin-gonic/gin" + + "openflare/common/response" +) + +// DecodeJSONBody decodes JSON reader to target +func DecodeJSONBody(body io.Reader, target any) error { + return json.NewDecoder(body).Decode(target) +} + +// OptionalJSON decodes optional JSON body of reader to target, allowing EOF +func OptionalJSON(body io.Reader, target any) error { + if err := json.NewDecoder(body).Decode(target); err != nil && !errors.Is(err, io.EOF) { + return err + } + return nil +} + +// IDParam parses "id" parameter from context path +func IDParam(c *gin.Context) (uint, bool) { + return IDParamByName(c, "id") +} + +// IDParamByName parses target parameter from context path +func IDParamByName(c *gin.Context, name string) (uint, bool) { + id, err := strconv.ParseUint(c.Param(name), 10, 64) + if err != nil || id == 0 { + response.RespondBadRequest(c, "") + return 0, false + } + return uint(id), true +} + +// JSON binds JSON body of context request to target +func JSON(c *gin.Context, target any) bool { + if err := DecodeJSONBody(c.Request.Body, target); err != nil { + response.RespondBadRequest(c, "") + return false + } + return true +} diff --git a/openflare_server/controller/config_version.go b/openflare_server/controller/config_version.go index e1568578..92aed5b6 100644 --- a/openflare_server/controller/config_version.go +++ b/openflare_server/controller/config_version.go @@ -1,6 +1,8 @@ package controller import ( + "openflare/common/response" + "openflare/controller/bind" "openflare/service" "github.com/gin-gonic/gin" @@ -16,10 +18,10 @@ import ( func GetConfigVersions(c *gin.Context) { versions, err := service.ListConfigVersions() if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, versions) + response.RespondSuccess(c, versions) } // GetConfigVersion godoc @@ -32,16 +34,16 @@ func GetConfigVersions(c *gin.Context) { // @Failure 400 {object} map[string]interface{} // @Router /api/config-versions/{id} [get] func GetConfigVersion(c *gin.Context) { - id, ok := parseIDParam(c) + id, ok := bind.IDParam(c) if !ok { return } version, err := service.GetConfigVersionDetail(id) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, version) + response.RespondSuccess(c, version) } // GetActiveConfigVersion godoc @@ -54,10 +56,10 @@ func GetConfigVersion(c *gin.Context) { func GetActiveConfigVersion(c *gin.Context) { version, err := service.GetActiveConfigVersion() if err != nil { - respondFailure(c, "当前没有激活版本") + response.RespondFailure(c, "当前没有激活版本") return } - respondSuccess(c, version) + response.RespondSuccess(c, version) } // PreviewConfigVersion godoc @@ -70,10 +72,10 @@ func GetActiveConfigVersion(c *gin.Context) { func PreviewConfigVersion(c *gin.Context) { preview, err := service.PreviewConfigVersion() if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, preview) + response.RespondSuccess(c, preview) } // DiffConfigVersion godoc @@ -86,10 +88,10 @@ func PreviewConfigVersion(c *gin.Context) { func DiffConfigVersion(c *gin.Context) { diff, err := service.DiffConfigVersion() if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, diff) + response.RespondSuccess(c, diff) } // PublishConfigVersion godoc @@ -104,10 +106,10 @@ func PublishConfigVersion(c *gin.Context) { force := c.Query("force") == "true" result, err := service.PublishConfigVersion(username, force) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, result.Version) + response.RespondSuccess(c, result.Version) } // ActivateConfigVersion godoc @@ -120,16 +122,16 @@ func PublishConfigVersion(c *gin.Context) { // @Failure 400 {object} map[string]interface{} // @Router /api/config-versions/{id}/activate [post] func ActivateConfigVersion(c *gin.Context) { - id, ok := parseIDParam(c) + id, ok := bind.IDParam(c) if !ok { return } version, err := service.ActivateConfigVersion(id) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, version) + response.RespondSuccess(c, version) } type CleanupConfigVersionRequest struct { @@ -147,17 +149,17 @@ type CleanupConfigVersionRequest struct { // @Router /api/config-versions/cleanup [post] func CleanupConfigVersions(c *gin.Context) { var req CleanupConfigVersionRequest - if !bindJSON(c, &req) { + if !bind.JSON(c, &req) { return } deletedCount, err := service.CleanupConfigVersions(req.KeepCount) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccessWithExtras(c, map[string]interface{}{"deleted_count": deletedCount}, gin.H{ + response.RespondSuccessWithExtras(c, map[string]interface{}{"deleted_count": deletedCount}, gin.H{ "message": "清理成功", }) } diff --git a/openflare_server/controller/dashboard.go b/openflare_server/controller/dashboard.go index 232ec25e..0f15aa07 100644 --- a/openflare_server/controller/dashboard.go +++ b/openflare_server/controller/dashboard.go @@ -1,6 +1,7 @@ package controller import ( + "openflare/common/response" "openflare/service" "github.com/gin-gonic/gin" @@ -40,10 +41,10 @@ type dashboardTrendsPayload struct { func GetDashboardOverview(c *gin.Context) { view, err := service.GetDashboardOverview() if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, compressDashboardOverview(view)) + response.RespondSuccess(c, compressDashboardOverview(view)) } func compressDashboardOverview(view *service.DashboardOverviewView) *dashboardOverviewPayload { diff --git a/openflare_server/controller/database.go b/openflare_server/controller/database.go index 3275c010..80ff0901 100644 --- a/openflare_server/controller/database.go +++ b/openflare_server/controller/database.go @@ -1,6 +1,8 @@ package controller import ( + "openflare/common/response" + "openflare/controller/bind" "openflare/service" "github.com/gin-gonic/gin" @@ -16,14 +18,14 @@ import ( // @Router /api/option/database/cleanup [post] func CleanupDatabaseObservability(c *gin.Context) { var input service.DatabaseCleanupInput - if err := decodeOptionalJSONBody(c.Request.Body, &input); err != nil { - respondBadRequest(c, "") + if err := bind.OptionalJSON(c.Request.Body, &input); err != nil { + response.RespondBadRequest(c, "") return } result, err := service.CleanupDatabaseObservability(input) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, result) + response.RespondSuccess(c, result) } diff --git a/openflare_server/controller/dns_account.go b/openflare_server/controller/dns_account.go index 0a9705f6..a44a2dc7 100644 --- a/openflare_server/controller/dns_account.go +++ b/openflare_server/controller/dns_account.go @@ -1,6 +1,8 @@ package controller import ( + "openflare/common/response" + "openflare/controller/bind" "openflare/model" "github.com/gin-gonic/gin" @@ -22,10 +24,10 @@ type DnsAccountInput struct { func GetDnsAccounts(c *gin.Context) { accounts, err := model.ListDnsAccounts() if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, accounts) + response.RespondSuccess(c, accounts) } // CreateDnsAccount godoc @@ -39,7 +41,7 @@ func GetDnsAccounts(c *gin.Context) { // @Router /api/dns-accounts/ [post] func CreateDnsAccount(c *gin.Context) { var input DnsAccountInput - if !bindJSON(c, &input) { + if !bind.JSON(c, &input) { return } @@ -50,11 +52,11 @@ func CreateDnsAccount(c *gin.Context) { } if err := account.Insert(); err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, account) + response.RespondSuccess(c, account) } // UpdateDnsAccount godoc @@ -68,19 +70,19 @@ func CreateDnsAccount(c *gin.Context) { // @Success 200 {object} map[string]interface{} // @Router /api/dns-accounts/{id}/update [post] func UpdateDnsAccount(c *gin.Context) { - id, ok := parseIDParam(c) + id, ok := bind.IDParam(c) if !ok { return } var input DnsAccountInput - if !bindJSON(c, &input) { + if !bind.JSON(c, &input) { return } account, err := model.GetDnsAccountByID(id) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } @@ -89,11 +91,11 @@ func UpdateDnsAccount(c *gin.Context) { account.Authorization = input.Authorization if err := account.Update(); err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, account) + response.RespondSuccess(c, account) } // DeleteDnsAccount godoc @@ -105,14 +107,14 @@ func UpdateDnsAccount(c *gin.Context) { // @Success 200 {object} map[string]interface{} // @Router /api/dns-accounts/{id}/delete [post] func DeleteDnsAccount(c *gin.Context) { - id, ok := parseIDParam(c) + id, ok := bind.IDParam(c) if !ok { return } account, err := model.GetDnsAccountByID(id) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } @@ -120,14 +122,14 @@ func DeleteDnsAccount(c *gin.Context) { var count int64 model.DB.Model(&model.TLSCertificate{}).Where("dns_account_id = ?", id).Count(&count) if count > 0 { - respondFailure(c, "该 DNS 账号已被证书使用,无法删除") + response.RespondFailure(c, "该 DNS 账号已被证书使用,无法删除") return } if err := account.Delete(); err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, nil) + response.RespondSuccess(c, nil) } diff --git a/openflare_server/controller/flared.go b/openflare_server/controller/flared.go index c48f7dbd..c28a0779 100644 --- a/openflare_server/controller/flared.go +++ b/openflare_server/controller/flared.go @@ -4,6 +4,8 @@ import ( "log/slog" "net" "openflare/common" + "openflare/common/response" + "openflare/controller/bind" "openflare/model" "openflare/service" "time" @@ -24,21 +26,21 @@ import ( // @Router /api/flared/heartbeat [post] func FlaredHeartbeat(c *gin.Context) { var payload service.FlaredHeartbeatPayload - if !bindJSON(c, &payload) { + if !bind.JSON(c, &payload) { return } authNode, ok := c.Get("flared_node") if !ok { - respondUnauthorized(c, "无权进行此操作,Tunnel Token 无效") + response.RespondUnauthorized(c, "无权进行此操作,Tunnel Token 无效") return } node := authNode.(*model.Node) - response, err := service.HeartbeatFlared(node, payload) + res, err := service.HeartbeatFlared(node, payload) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, response) + response.RespondSuccess(c, res) } // FlaredGetActiveConfig godoc @@ -51,16 +53,16 @@ func FlaredHeartbeat(c *gin.Context) { func FlaredGetActiveConfig(c *gin.Context) { authNode, ok := c.Get("flared_node") if !ok { - respondUnauthorized(c, "无权进行此操作,Tunnel Token 无效") + response.RespondUnauthorized(c, "无权进行此操作,Tunnel Token 无效") return } node := authNode.(*model.Node) config, err := service.GetFlaredTunnelConfig(node) if err != nil { - respondFailure(c, "无法生成隧道配置: "+err.Error()) + response.RespondFailure(c, "无法生成隧道配置: "+err.Error()) return } - respondSuccess(c, config) + response.RespondSuccess(c, config) } // FlaredReportApplyLog godoc @@ -74,7 +76,7 @@ func FlaredGetActiveConfig(c *gin.Context) { // @Router /api/flared/apply-log [post] func FlaredReportApplyLog(c *gin.Context) { var payload service.ApplyLogPayload - if !bindJSON(c, &payload) { + if !bind.JSON(c, &payload) { return } if authNode, ok := c.Get("flared_node"); ok { @@ -82,10 +84,10 @@ func FlaredReportApplyLog(c *gin.Context) { } log, err := service.ReportApplyLog(payload) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, log) + response.RespondSuccess(c, log) } // FlaredWebSocket godoc @@ -96,7 +98,7 @@ func FlaredReportApplyLog(c *gin.Context) { func FlaredWebSocket(c *gin.Context) { authNode, ok := c.Get("flared_node") if !ok { - respondUnauthorized(c, "无权进行此操作,Tunnel Token 无效") + response.RespondUnauthorized(c, "无权进行此操作,Tunnel Token 无效") return } node := authNode.(*model.Node) diff --git a/openflare_server/controller/geoip.go b/openflare_server/controller/geoip.go index 6e7c65ec..ef7510a4 100644 --- a/openflare_server/controller/geoip.go +++ b/openflare_server/controller/geoip.go @@ -1,6 +1,8 @@ package controller import ( + "openflare/common/response" + "openflare/controller/bind" "openflare/service" "github.com/gin-gonic/gin" @@ -22,14 +24,14 @@ type geoIPLookupRequest struct { // @Router /api/option/geoip/lookup [post] func LookupGeoIP(c *gin.Context) { var request geoIPLookupRequest - if !bindJSON(c, &request) { + if !bind.JSON(c, &request) { return } view, err := service.LookupGeoIP(request.Provider, request.IP) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, view) + response.RespondSuccess(c, view) } diff --git a/openflare_server/controller/github.go b/openflare_server/controller/github.go index 124b7fac..68447c2c 100644 --- a/openflare_server/controller/github.go +++ b/openflare_server/controller/github.go @@ -8,6 +8,7 @@ import ( "log/slog" "net/http" "openflare/common" + "openflare/common/response" "openflare/model" "time" @@ -84,13 +85,13 @@ func GitHubOAuth(c *gin.Context) { } if !common.GitHubOAuthEnabled { - respondFailure(c, "管理员未开启通过 GitHub 登录以及注册") + response.RespondFailure(c, "管理员未开启通过 GitHub 登录以及注册") return } code := c.Query("code") githubUser, err := getGitHubUserInfoByCode(code) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } user := model.User{ @@ -99,16 +100,16 @@ func GitHubOAuth(c *gin.Context) { if model.IsGitHubIdAlreadyTaken(user.GitHubId) { err := user.FillUserByGitHubId() if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } } else { - respondFailure(c, "管理员关闭了新用户注册") + response.RespondFailure(c, "管理员关闭了新用户注册") return } if user.Status != common.UserStatusEnabled { - respondFailure(c, "用户已被封禁") + response.RespondFailure(c, "用户已被封禁") return } setupLogin(&user, c) @@ -116,38 +117,38 @@ func GitHubOAuth(c *gin.Context) { func GitHubBind(c *gin.Context) { if !common.GitHubOAuthEnabled { - respondFailure(c, "管理员未开启通过 GitHub 登录以及注册") + response.RespondFailure(c, "管理员未开启通过 GitHub 登录以及注册") return } code := c.Query("code") githubUser, err := getGitHubUserInfoByCode(code) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } user := model.User{ GitHubId: githubUser.Login, } if model.IsGitHubIdAlreadyTaken(user.GitHubId) { - respondFailure(c, "该 GitHub 账户已被绑定") + response.RespondFailure(c, "该 GitHub 账户已被绑定") return } currentUser := currentUserFromOpenFlareToken(c) if currentUser == nil { - respondFailure(c, "无权进行此操作,未登录或 token 无效") + response.RespondFailure(c, "无权进行此操作,未登录或 token 无效") return } user.Id = currentUser.Id err = user.FillUserById() if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } user.GitHubId = githubUser.Login err = user.Update(false) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccessMessage(c, "bind") + response.RespondSuccessMessage(c, "bind") } diff --git a/openflare_server/controller/managed_domain.go b/openflare_server/controller/managed_domain.go index 5b192f01..ca7df654 100644 --- a/openflare_server/controller/managed_domain.go +++ b/openflare_server/controller/managed_domain.go @@ -1,6 +1,8 @@ package controller import ( + "openflare/common/response" + "openflare/controller/bind" "openflare/service" "strings" @@ -17,10 +19,10 @@ import ( func GetManagedDomains(c *gin.Context) { domains, err := service.ListManagedDomains() if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, domains) + response.RespondSuccess(c, domains) } // CreateManagedDomain godoc @@ -35,15 +37,15 @@ func GetManagedDomains(c *gin.Context) { // @Router /api/managed-domains/ [post] func CreateManagedDomain(c *gin.Context) { var input service.ManagedDomainInput - if !bindJSON(c, &input) { + if !bind.JSON(c, &input) { return } domain, err := service.CreateManagedDomain(input) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, domain) + response.RespondSuccess(c, domain) } // UpdateManagedDomain godoc @@ -58,20 +60,20 @@ func CreateManagedDomain(c *gin.Context) { // @Failure 400 {object} map[string]interface{} // @Router /api/managed-domains/{id}/update [post] func UpdateManagedDomain(c *gin.Context) { - id, ok := parseIDParam(c) + id, ok := bind.IDParam(c) if !ok { return } var input service.ManagedDomainInput - if !bindJSON(c, &input) { + if !bind.JSON(c, &input) { return } domain, err := service.UpdateManagedDomain(id, input) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, domain) + response.RespondSuccess(c, domain) } // DeleteManagedDomain godoc @@ -84,15 +86,15 @@ func UpdateManagedDomain(c *gin.Context) { // @Failure 400 {object} map[string]interface{} // @Router /api/managed-domains/{id}/delete [post] func DeleteManagedDomain(c *gin.Context) { - id, ok := parseIDParam(c) + id, ok := bind.IDParam(c) if !ok { return } if err := service.DeleteManagedDomain(id); err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, nil) + response.RespondSuccess(c, nil) } // MatchManagedDomainCertificate godoc @@ -107,8 +109,8 @@ func MatchManagedDomainCertificate(c *gin.Context) { domain := strings.TrimSpace(c.Query("domain")) result, err := service.MatchManagedDomainCertificate(domain) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, result) + response.RespondSuccess(c, result) } diff --git a/openflare_server/controller/misc.go b/openflare_server/controller/misc.go index 3e6eb2b0..432a53e2 100644 --- a/openflare_server/controller/misc.go +++ b/openflare_server/controller/misc.go @@ -3,6 +3,8 @@ package controller import ( "fmt" "openflare/common" + "openflare/common/response" + "openflare/controller/bind" "openflare/model" "openflare/service" "openflare/utils/mail" @@ -23,7 +25,7 @@ func GetStatus(c *gin.Context) { if err != nil { authSources = []service.PublicAuthSource{} } - respondSuccess(c, gin.H{ + response.RespondSuccess(c, gin.H{ "version": common.Version, "start_time": common.StartTime, "email_verification": common.EmailVerificationEnabled, @@ -43,23 +45,23 @@ func GetStatus(c *gin.Context) { func GetNotice(c *gin.Context) { common.OptionMapRWMutex.RLock() defer common.OptionMapRWMutex.RUnlock() - respondSuccess(c, common.OptionMap["Notice"]) + response.RespondSuccess(c, common.OptionMap["Notice"]) } func GetAbout(c *gin.Context) { common.OptionMapRWMutex.RLock() defer common.OptionMapRWMutex.RUnlock() - respondSuccess(c, common.OptionMap["About"]) + response.RespondSuccess(c, common.OptionMap["About"]) } func SendEmailVerification(c *gin.Context) { email := c.Query("email") if err := validation.Validate.Var(email, "required,email"); err != nil { - respondFailure(c, "无效的参数") + response.RespondFailure(c, "无效的参数") return } if model.IsEmailAlreadyTaken(email) { - respondFailure(c, "邮箱地址已被占用") + response.RespondFailure(c, "邮箱地址已被占用") return } code := security.GenerateVerificationCode(6) @@ -77,20 +79,20 @@ func SendEmailVerification(c *gin.Context) { } err := mail.SendEmail(cfg, subject, email, content) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccessMessage(c, "") + response.RespondSuccessMessage(c, "") } func SendPasswordResetEmail(c *gin.Context) { email := c.Query("email") if err := validation.Validate.Var(email, "required,email"); err != nil { - respondFailure(c, "无效的参数") + response.RespondFailure(c, "无效的参数") return } if !model.IsEmailAlreadyTaken(email) { - respondFailure(c, "该邮箱地址未注册") + response.RespondFailure(c, "该邮箱地址未注册") return } code := security.GenerateVerificationCode(0) @@ -109,10 +111,10 @@ func SendPasswordResetEmail(c *gin.Context) { } err := mail.SendEmail(cfg, subject, email, content) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccessMessage(c, "") + response.RespondSuccessMessage(c, "") } type PasswordResetRequest struct { @@ -122,23 +124,23 @@ type PasswordResetRequest struct { func ResetPassword(c *gin.Context) { var req PasswordResetRequest - if !bindJSON(c, &req) { + if !bind.JSON(c, &req) { return } if req.Email == "" || req.Token == "" { - respondFailure(c, "无效的参数") + response.RespondFailure(c, "无效的参数") return } if !security.VerifyCodeWithKey(req.Email, req.Token, security.PasswordResetPurpose) { - respondFailure(c, "重置链接非法或已过期") + response.RespondFailure(c, "重置链接非法或已过期") return } password := security.GenerateVerificationCode(12) err := model.ResetUserPasswordByEmail(req.Email, password) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } security.DeleteKey(req.Email, security.PasswordResetPurpose) - respondSuccess(c, password) + response.RespondSuccess(c, password) } diff --git a/openflare_server/controller/node.go b/openflare_server/controller/node.go index eaf6224c..03820bf5 100644 --- a/openflare_server/controller/node.go +++ b/openflare_server/controller/node.go @@ -1,6 +1,8 @@ package controller import ( + "openflare/common/response" + "openflare/controller/bind" "openflare/service" "github.com/gin-gonic/gin" @@ -28,16 +30,16 @@ type nodeObservabilityQuery struct { // @Router /api/nodes/ [post] func CreateNode(c *gin.Context) { var input service.NodeInput - if !bindJSON(c, &input) { + if !bind.JSON(c, &input) { return } node, err := service.CreateNode(input) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, node) + response.RespondSuccess(c, node) } // GetNodeBootstrapToken godoc @@ -50,10 +52,10 @@ func CreateNode(c *gin.Context) { func GetNodeBootstrapToken(c *gin.Context) { bootstrap, err := service.GetNodeBootstrapView() if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, bootstrap) + response.RespondSuccess(c, bootstrap) } // RotateNodeBootstrapToken godoc @@ -66,10 +68,10 @@ func GetNodeBootstrapToken(c *gin.Context) { func RotateNodeBootstrapToken(c *gin.Context) { bootstrap, err := service.RotateGlobalDiscoveryToken() if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, bootstrap) + response.RespondSuccess(c, bootstrap) } // UpdateNode godoc @@ -84,22 +86,22 @@ func RotateNodeBootstrapToken(c *gin.Context) { // @Failure 400 {object} map[string]interface{} // @Router /api/nodes/{id}/update [post] func UpdateNode(c *gin.Context) { - id, ok := parseIDParam(c) + id, ok := bind.IDParam(c) if !ok { return } var input service.NodeInput - if !bindJSON(c, &input) { + if !bind.JSON(c, &input) { return } node, err := service.UpdateNode(id, input) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, node) + response.RespondSuccess(c, node) } // DeleteNode godoc @@ -112,16 +114,16 @@ func UpdateNode(c *gin.Context) { // @Failure 400 {object} map[string]interface{} // @Router /api/nodes/{id}/delete [post] func DeleteNode(c *gin.Context) { - id, ok := parseIDParam(c) + id, ok := bind.IDParam(c) if !ok { return } if err := service.DeleteNode(id); err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccessMessage(c, "") + response.RespondSuccessMessage(c, "") } // RequestNodeAgentUpdate godoc @@ -134,15 +136,15 @@ func DeleteNode(c *gin.Context) { // @Failure 400 {object} map[string]interface{} // @Router /api/nodes/{id}/agent-update [post] func RequestNodeAgentUpdate(c *gin.Context) { - id, ok := parseIDParam(c) + id, ok := bind.IDParam(c) if !ok { return } var request nodeAgentUpdateRequest if c.Request.ContentLength > 0 { - if err := decodeOptionalJSONBody(c.Request.Body, &request); err != nil { - respondBadRequest(c, "") + if err := bind.OptionalJSON(c.Request.Body, &request); err != nil { + response.RespondBadRequest(c, "") return } } @@ -152,10 +154,10 @@ func RequestNodeAgentUpdate(c *gin.Context) { TagName: request.TagName, }) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, node) + response.RespondSuccess(c, node) } // RequestNodeOpenrestyRestart godoc @@ -168,17 +170,17 @@ func RequestNodeAgentUpdate(c *gin.Context) { // @Failure 400 {object} map[string]interface{} // @Router /api/nodes/{id}/openresty-restart [post] func RequestNodeOpenrestyRestart(c *gin.Context) { - id, ok := parseIDParam(c) + id, ok := bind.IDParam(c) if !ok { return } node, err := service.RequestNodeOpenrestyRestart(id) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, node) + response.RespondSuccess(c, node) } // RequestNodeForceSync godoc @@ -191,17 +193,17 @@ func RequestNodeOpenrestyRestart(c *gin.Context) { // @Failure 400 {object} map[string]interface{} // @Router /api/nodes/{id}/force-sync [post] func RequestNodeForceSync(c *gin.Context) { - id, ok := parseIDParam(c) + id, ok := bind.IDParam(c) if !ok { return } node, err := service.RequestNodeForceSync(id) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, node) + response.RespondSuccess(c, node) } // GetNodeAgentRelease godoc @@ -215,17 +217,17 @@ func RequestNodeForceSync(c *gin.Context) { // @Failure 400 {object} map[string]interface{} // @Router /api/nodes/{id}/agent-release [get] func GetNodeAgentRelease(c *gin.Context) { - id, ok := parseIDParam(c) + id, ok := bind.IDParam(c) if !ok { return } release, err := service.GetNodeAgentRelease(c.Request.Context(), id, c.Query("channel")) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, release) + response.RespondSuccess(c, release) } // GetNodeObservability godoc @@ -240,14 +242,14 @@ func GetNodeAgentRelease(c *gin.Context) { // @Failure 400 {object} map[string]interface{} // @Router /api/nodes/{id}/observability [get] func GetNodeObservability(c *gin.Context) { - id, ok := parseIDParam(c) + id, ok := bind.IDParam(c) if !ok { return } var query nodeObservabilityQuery if err := c.ShouldBindQuery(&query); err != nil { - respondBadRequest(c, "") + response.RespondBadRequest(c, "") return } @@ -256,10 +258,10 @@ func GetNodeObservability(c *gin.Context) { Limit: query.Limit, }) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, view) + response.RespondSuccess(c, view) } // CleanupNodeHealthEvents godoc @@ -272,15 +274,15 @@ func GetNodeObservability(c *gin.Context) { // @Failure 400 {object} map[string]interface{} // @Router /api/nodes/{id}/observability/cleanup [post] func CleanupNodeHealthEvents(c *gin.Context) { - id, ok := parseIDParam(c) + id, ok := bind.IDParam(c) if !ok { return } result, err := service.CleanupNodeHealthEvents(id) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, result) + response.RespondSuccess(c, result) } diff --git a/openflare_server/controller/option.go b/openflare_server/controller/option.go index 648c10d1..01026f28 100644 --- a/openflare_server/controller/option.go +++ b/openflare_server/controller/option.go @@ -3,6 +3,8 @@ package controller import ( "fmt" "openflare/common" + "openflare/common/response" + "openflare/controller/bind" "openflare/model" "openflare/service" "openflare/utils" @@ -356,7 +358,7 @@ func GetOptions(c *gin.Context) { }) } common.OptionMapRWMutex.RUnlock() - respondSuccess(c, options) + response.RespondSuccess(c, options) } // UpdateOption godoc @@ -370,20 +372,20 @@ func GetOptions(c *gin.Context) { // @Router /api/option/update [post] func UpdateOption(c *gin.Context) { var option model.Option - if !bindJSON(c, &option) { + if !bind.JSON(c, &option) { return } state := buildOptionValidationState([]model.Option{option}) if err := validateOptionWithState(option, state); err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } err := model.UpdateOption(option.Key, option.Value) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccessMessage(c, "") + response.RespondSuccessMessage(c, "") } // UpdateOptionsBatch godoc @@ -397,18 +399,18 @@ func UpdateOption(c *gin.Context) { // @Router /api/option/update-batch [post] func UpdateOptionsBatch(c *gin.Context) { var payload optionBatchPayload - if !bindJSON(c, &payload) { + if !bind.JSON(c, &payload) { return } if len(payload.Options) == 0 { - respondBadRequest(c, "无效的参数") + response.RespondBadRequest(c, "无效的参数") return } if err := updateOptions(payload.Options); err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccessMessage(c, "") + response.RespondSuccessMessage(c, "") } diff --git a/openflare_server/controller/origin.go b/openflare_server/controller/origin.go index c98f2354..cd2505c9 100644 --- a/openflare_server/controller/origin.go +++ b/openflare_server/controller/origin.go @@ -1,6 +1,8 @@ package controller import ( + "openflare/common/response" + "openflare/controller/bind" "openflare/service" "github.com/gin-gonic/gin" @@ -9,63 +11,63 @@ import ( func GetOrigins(c *gin.Context) { origins, err := service.ListOrigins() if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, origins) + response.RespondSuccess(c, origins) } func GetOrigin(c *gin.Context) { - id, ok := parseIDParam(c) + id, ok := bind.IDParam(c) if !ok { return } origin, err := service.GetOriginDetail(id) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, origin) + response.RespondSuccess(c, origin) } func CreateOrigin(c *gin.Context) { var input service.OriginInput - if !bindJSON(c, &input) { + if !bind.JSON(c, &input) { return } origin, err := service.CreateOrigin(input) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, origin) + response.RespondSuccess(c, origin) } func UpdateOrigin(c *gin.Context) { - id, ok := parseIDParam(c) + id, ok := bind.IDParam(c) if !ok { return } var input service.OriginInput - if !bindJSON(c, &input) { + if !bind.JSON(c, &input) { return } origin, err := service.UpdateOrigin(id, input) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, origin) + response.RespondSuccess(c, origin) } func DeleteOrigin(c *gin.Context) { - id, ok := parseIDParam(c) + id, ok := bind.IDParam(c) if !ok { return } if err := service.DeleteOrigin(id); err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, nil) + response.RespondSuccess(c, nil) } diff --git a/openflare_server/controller/pages.go b/openflare_server/controller/pages.go index 16888979..84d0f4dc 100644 --- a/openflare_server/controller/pages.go +++ b/openflare_server/controller/pages.go @@ -1,6 +1,8 @@ package controller import ( + "openflare/common/response" + "openflare/controller/bind" "openflare/service" "github.com/gin-gonic/gin" @@ -9,88 +11,88 @@ import ( func ListPagesProjects(c *gin.Context) { projects, err := service.ListPagesProjects() if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, projects) + response.RespondSuccess(c, projects) } func GetPagesProject(c *gin.Context) { - id, ok := parseIDParam(c) + id, ok := bind.IDParam(c) if !ok { return } project, err := service.GetPagesProject(id) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, project) + response.RespondSuccess(c, project) } func CreatePagesProject(c *gin.Context) { var input service.PagesProjectInput - if !bindJSON(c, &input) { + if !bind.JSON(c, &input) { return } project, err := service.CreatePagesProject(input) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, project) + response.RespondSuccess(c, project) } func UpdatePagesProject(c *gin.Context) { - id, ok := parseIDParam(c) + id, ok := bind.IDParam(c) if !ok { return } var input service.PagesProjectInput - if !bindJSON(c, &input) { + if !bind.JSON(c, &input) { return } project, err := service.UpdatePagesProject(id, input) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, project) + response.RespondSuccess(c, project) } func DeletePagesProject(c *gin.Context) { - id, ok := parseIDParam(c) + id, ok := bind.IDParam(c) if !ok { return } if err := service.DeletePagesProject(id); err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, nil) + response.RespondSuccess(c, nil) } func ListPagesDeployments(c *gin.Context) { - id, ok := parseIDParam(c) + id, ok := bind.IDParam(c) if !ok { return } deployments, err := service.ListPagesProjectDeployments(id) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, deployments) + response.RespondSuccess(c, deployments) } func UploadPagesDeployment(c *gin.Context) { - id, ok := parseIDParam(c) + id, ok := bind.IDParam(c) if !ok { return } file, err := c.FormFile("package") if err != nil { - respondBadRequest(c, "缺少 Pages 部署包") + response.RespondBadRequest(c, "缺少 Pages 部署包") return } deployment, err := service.UploadPagesDeployment( @@ -101,66 +103,66 @@ func UploadPagesDeployment(c *gin.Context) { c.GetString("username"), ) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, deployment) + response.RespondSuccess(c, deployment) } func ActivatePagesDeployment(c *gin.Context) { - projectID, ok := parseIDParam(c) + projectID, ok := bind.IDParam(c) if !ok { return } - deploymentID, ok := parseIDParamByName(c, "deployment_id") + deploymentID, ok := bind.IDParamByName(c, "deployment_id") if !ok { return } project, err := service.ActivatePagesDeployment(projectID, deploymentID) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, project) + response.RespondSuccess(c, project) } func DeletePagesDeployment(c *gin.Context) { - projectID, ok := parseIDParam(c) + projectID, ok := bind.IDParam(c) if !ok { return } - deploymentID, ok := parseIDParamByName(c, "deployment_id") + deploymentID, ok := bind.IDParamByName(c, "deployment_id") if !ok { return } if err := service.DeletePagesDeployment(projectID, deploymentID); err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, nil) + response.RespondSuccess(c, nil) } func ListPagesDeploymentFiles(c *gin.Context) { - deploymentID, ok := parseIDParamByName(c, "deployment_id") + deploymentID, ok := bind.IDParamByName(c, "deployment_id") if !ok { return } files, err := service.ListPagesDeploymentFiles(deploymentID) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, files) + response.RespondSuccess(c, files) } func AgentDownloadPagesDeploymentPackage(c *gin.Context) { - deploymentID, ok := parseIDParamByName(c, "deployment_id") + deploymentID, ok := bind.IDParamByName(c, "deployment_id") if !ok { return } filePath, fileName, err := service.GetPagesDeploymentPackagePath(deploymentID) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } c.Header("Content-Disposition", "attachment; filename="+fileName) diff --git a/openflare_server/controller/proxy_route.go b/openflare_server/controller/proxy_route.go index 7be2d13a..05c60ed6 100644 --- a/openflare_server/controller/proxy_route.go +++ b/openflare_server/controller/proxy_route.go @@ -1,6 +1,8 @@ package controller import ( + "openflare/common/response" + "openflare/controller/bind" "openflare/service" "github.com/gin-gonic/gin" @@ -16,10 +18,10 @@ import ( func GetProxyRoutes(c *gin.Context) { routes, err := service.ListProxyRoutes() if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, routes) + response.RespondSuccess(c, routes) } // GetProxyRoute godoc @@ -32,16 +34,16 @@ func GetProxyRoutes(c *gin.Context) { // @Failure 400 {object} map[string]interface{} // @Router /api/proxy-routes/{id} [get] func GetProxyRoute(c *gin.Context) { - id, ok := parseIDParam(c) + id, ok := bind.IDParam(c) if !ok { return } route, err := service.GetProxyRoute(id) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, route) + response.RespondSuccess(c, route) } // CreateProxyRoute godoc @@ -56,15 +58,15 @@ func GetProxyRoute(c *gin.Context) { // @Router /api/proxy-routes/ [post] func CreateProxyRoute(c *gin.Context) { var input service.ProxyRouteInput - if !bindJSON(c, &input) { + if !bind.JSON(c, &input) { return } route, err := service.CreateProxyRoute(input) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, route) + response.RespondSuccess(c, route) } // UpdateProxyRoute godoc @@ -79,20 +81,20 @@ func CreateProxyRoute(c *gin.Context) { // @Failure 400 {object} map[string]interface{} // @Router /api/proxy-routes/{id}/update [post] func UpdateProxyRoute(c *gin.Context) { - id, ok := parseIDParam(c) + id, ok := bind.IDParam(c) if !ok { return } var input service.ProxyRouteInput - if !bindJSON(c, &input) { + if !bind.JSON(c, &input) { return } route, err := service.UpdateProxyRoute(id, input) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, route) + response.RespondSuccess(c, route) } // DeleteProxyRoute godoc @@ -105,13 +107,13 @@ func UpdateProxyRoute(c *gin.Context) { // @Failure 400 {object} map[string]interface{} // @Router /api/proxy-routes/{id}/delete [post] func DeleteProxyRoute(c *gin.Context) { - id, ok := parseIDParam(c) + id, ok := bind.IDParam(c) if !ok { return } if err := service.DeleteProxyRoute(id); err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, nil) + response.RespondSuccess(c, nil) } diff --git a/openflare_server/controller/relay.go b/openflare_server/controller/relay.go index 3c4fbc2a..12bd7693 100644 --- a/openflare_server/controller/relay.go +++ b/openflare_server/controller/relay.go @@ -3,6 +3,8 @@ package controller import ( "log/slog" "net" + "openflare/common/response" + "openflare/controller/bind" "openflare/model" "openflare/service" "time" @@ -23,22 +25,22 @@ import ( // @Router /api/relay/heartbeat [post] func RelayHeartbeat(c *gin.Context) { var payload service.RelayHeartbeatPayload - if !bindJSON(c, &payload) { + if !bind.JSON(c, &payload) { return } payload.IP = service.ResolveReportedNodeIP(payload.IP, c.Request.RemoteAddr) authNode, ok := c.Get("relay_node") if !ok { - respondUnauthorized(c, "无权进行此操作") + response.RespondUnauthorized(c, "无权进行此操作") return } node := authNode.(*model.Node) result, err := service.HeartbeatRelay(node, payload) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, result) + response.RespondSuccess(c, result) } // RelayWebSocket godoc @@ -49,7 +51,7 @@ func RelayHeartbeat(c *gin.Context) { func RelayWebSocket(c *gin.Context) { authNode, ok := c.Get("relay_node") if !ok { - respondUnauthorized(c, "无权进行此操作") + response.RespondUnauthorized(c, "无权进行此操作") return } node := authNode.(*model.Node) diff --git a/openflare_server/controller/response.go b/openflare_server/controller/response.go deleted file mode 100644 index 0492293a..00000000 --- a/openflare_server/controller/response.go +++ /dev/null @@ -1,68 +0,0 @@ -package controller - -import ( - "encoding/json" - "errors" - "io" - "strconv" - - "github.com/gin-gonic/gin" - - "openflare/common/response" -) - -func respondSuccess(c *gin.Context, data any) { - response.RespondSuccess(c, data) -} - -func respondSuccessWithExtras(c *gin.Context, data any, extras gin.H) { - response.RespondSuccessWithExtras(c, data, extras) -} - -func respondSuccessMessage(c *gin.Context, message string) { - response.RespondSuccessMessage(c, message) -} - -func respondFailure(c *gin.Context, message string) { - response.RespondFailure(c, message) -} - -func respondBadRequest(c *gin.Context, message string) { - response.RespondBadRequest(c, message) -} - -func respondUnauthorized(c *gin.Context, message string) { - response.RespondUnauthorized(c, message) -} - -func decodeJSONBody(body io.Reader, target any) error { - return json.NewDecoder(body).Decode(target) -} - -func decodeOptionalJSONBody(body io.Reader, target any) error { - if err := json.NewDecoder(body).Decode(target); err != nil && !errors.Is(err, io.EOF) { - return err - } - return nil -} - -func parseIDParam(c *gin.Context) (uint, bool) { - return parseIDParamByName(c, "id") -} - -func parseIDParamByName(c *gin.Context, name string) (uint, bool) { - id, err := strconv.ParseUint(c.Param(name), 10, 64) - if err != nil || id == 0 { - respondBadRequest(c, "") - return 0, false - } - return uint(id), true -} - -func bindJSON(c *gin.Context, target any) bool { - if err := decodeJSONBody(c.Request.Body, target); err != nil { - respondBadRequest(c, "") - return false - } - return true -} diff --git a/openflare_server/controller/tls_certificate.go b/openflare_server/controller/tls_certificate.go index e6aec555..ca8f56e9 100644 --- a/openflare_server/controller/tls_certificate.go +++ b/openflare_server/controller/tls_certificate.go @@ -1,6 +1,8 @@ package controller import ( + "openflare/common/response" + "openflare/controller/bind" "openflare/service" "github.com/gin-gonic/gin" @@ -16,10 +18,10 @@ import ( func GetTLSCertificates(c *gin.Context) { certificates, err := service.ListTLSCertificates() if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, certificates) + response.RespondSuccess(c, certificates) } // GetTLSCertificate godoc @@ -32,17 +34,17 @@ func GetTLSCertificates(c *gin.Context) { // @Failure 400 {object} map[string]interface{} // @Router /api/tls-certificates/{id} [get] func GetTLSCertificate(c *gin.Context) { - id, ok := parseIDParam(c) + id, ok := bind.IDParam(c) if !ok { return } certificate, err := service.GetTLSCertificate(id) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, certificate) + response.RespondSuccess(c, certificate) } // GetTLSCertificateContent godoc @@ -55,17 +57,17 @@ func GetTLSCertificate(c *gin.Context) { // @Failure 400 {object} map[string]interface{} // @Router /api/tls-certificates/{id}/content [get] func GetTLSCertificateContent(c *gin.Context) { - id, ok := parseIDParam(c) + id, ok := bind.IDParam(c) if !ok { return } content, err := service.GetTLSCertificateContent(id) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, content) + response.RespondSuccess(c, content) } // CreateTLSCertificate godoc @@ -80,15 +82,15 @@ func GetTLSCertificateContent(c *gin.Context) { // @Router /api/tls-certificates/ [post] func CreateTLSCertificate(c *gin.Context) { var input service.TLSCertificateInput - if !bindJSON(c, &input) { + if !bind.JSON(c, &input) { return } certificate, err := service.CreateTLSCertificate(input) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, certificate) + response.RespondSuccess(c, certificate) } // UpdateTLSCertificate godoc @@ -103,22 +105,22 @@ func CreateTLSCertificate(c *gin.Context) { // @Failure 400 {object} map[string]interface{} // @Router /api/tls-certificates/{id}/update [post] func UpdateTLSCertificate(c *gin.Context) { - id, ok := parseIDParam(c) + id, ok := bind.IDParam(c) if !ok { return } var input service.TLSCertificateInput - if !bindJSON(c, &input) { + if !bind.JSON(c, &input) { return } certificate, err := service.UpdateTLSCertificate(id, input) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, certificate) + response.RespondSuccess(c, certificate) } // ImportTLSCertificateFile godoc @@ -139,20 +141,20 @@ func ImportTLSCertificateFile(c *gin.Context) { remark := c.PostForm("remark") certFile, err := c.FormFile("cert_file") if err != nil { - respondBadRequest(c, "缺少证书文件") + response.RespondBadRequest(c, "缺少证书文件") return } keyFile, err := c.FormFile("key_file") if err != nil { - respondBadRequest(c, "缺少私钥文件") + response.RespondBadRequest(c, "缺少私钥文件") return } certificate, err := service.CreateTLSCertificateFromFiles(name, certFile, keyFile, remark) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, certificate) + response.RespondSuccess(c, certificate) } // DeleteTLSCertificate godoc @@ -165,15 +167,15 @@ func ImportTLSCertificateFile(c *gin.Context) { // @Failure 400 {object} map[string]interface{} // @Router /api/tls-certificates/{id}/delete [post] func DeleteTLSCertificate(c *gin.Context) { - id, ok := parseIDParam(c) + id, ok := bind.IDParam(c) if !ok { return } if err := service.DeleteTLSCertificate(id); err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, nil) + response.RespondSuccess(c, nil) } // ApplyTLSCertificate godoc @@ -188,15 +190,15 @@ func DeleteTLSCertificate(c *gin.Context) { // @Router /api/tls-certificates/apply [post] func ApplyTLSCertificate(c *gin.Context) { var input service.TLSApplyInput - if !bindJSON(c, &input) { + if !bind.JSON(c, &input) { return } certificate, err := service.ApplyTLSCertificate(input) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, certificate) + response.RespondSuccess(c, certificate) } // UpdateAcmeCertificate godoc @@ -211,21 +213,21 @@ func ApplyTLSCertificate(c *gin.Context) { // @Failure 400 {object} map[string]interface{} // @Router /api/tls-certificates/{id}/update-acme [post] func UpdateAcmeCertificate(c *gin.Context) { - id, ok := parseIDParam(c) + id, ok := bind.IDParam(c) if !ok { return } var input service.TLSApplyInput - if !bindJSON(c, &input) { + if !bind.JSON(c, &input) { return } certificate, err := service.UpdateAcmeCertificate(id, input) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, certificate) + response.RespondSuccess(c, certificate) } // ConvertTLSCertificateToAcme godoc @@ -240,21 +242,21 @@ func UpdateAcmeCertificate(c *gin.Context) { // @Failure 400 {object} map[string]interface{} // @Router /api/tls-certificates/{id}/convert-acme [post] func ConvertTLSCertificateToAcme(c *gin.Context) { - id, ok := parseIDParam(c) + id, ok := bind.IDParam(c) if !ok { return } var input service.TLSApplyInput - if !bindJSON(c, &input) { + if !bind.JSON(c, &input) { return } certificate, err := service.ConvertTLSCertificateToAcme(id, input) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, certificate) + response.RespondSuccess(c, certificate) } // RenewTLSCertificate godoc @@ -267,14 +269,14 @@ func ConvertTLSCertificateToAcme(c *gin.Context) { // @Failure 400 {object} map[string]interface{} // @Router /api/tls-certificates/{id}/renew [post] func RenewTLSCertificate(c *gin.Context) { - id, ok := parseIDParam(c) + id, ok := bind.IDParam(c) if !ok { return } certificate, err := service.RenewTLSCertificate(id) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, certificate) + response.RespondSuccess(c, certificate) } diff --git a/openflare_server/controller/update.go b/openflare_server/controller/update.go index 2ceb97cf..6510ddb6 100644 --- a/openflare_server/controller/update.go +++ b/openflare_server/controller/update.go @@ -1,6 +1,8 @@ package controller import ( + "openflare/common/response" + "openflare/controller/bind" "openflare/service" "time" @@ -26,10 +28,10 @@ type serverUpgradeRequest struct { func GetLatestRelease(c *gin.Context) { release, err := service.GetLatestServerRelease(c.Request.Context(), c.Query("channel")) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, release) + response.RespondSuccess(c, release) } // UpgradeServer godoc @@ -41,18 +43,18 @@ func GetLatestRelease(c *gin.Context) { func UpgradeServer(c *gin.Context) { var request serverUpgradeRequest if c.Request.ContentLength > 0 { - if err := decodeOptionalJSONBody(c.Request.Body, &request); err != nil { - respondBadRequest(c, "无效的参数") + if err := bind.OptionalJSON(c.Request.Body, &request); err != nil { + response.RespondBadRequest(c, "无效的参数") return } } release, err := service.ScheduleServerUpgrade(request.Channel) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccessWithExtras(c, release, gin.H{ + response.RespondSuccessWithExtras(c, release, gin.H{ "message": "服务升级任务已启动,下载完成后将自动重启。", }) } @@ -101,18 +103,18 @@ func StreamServerUpgradeLogs(c *gin.Context) { // @Success 200 {object} map[string]interface{} // @Router /api/update/manual-upload [post] func UploadManualServerBinary(c *gin.Context) { - respondFailure(c, "手动升级功能已禁用") + response.RespondFailure(c, "手动升级功能已禁用") return // //fileHeader, err := c.FormFile("binary") //if err != nil { - // respondFailure(c, "请先选择要上传的服务端二进制文件。") + // response.RespondFailure(c, "请先选择要上传的服务端二进制文件。") // return //} // //file, err := fileHeader.Open() //if err != nil { - // respondFailure(c, "读取上传文件失败。") + // response.RespondFailure(c, "读取上传文件失败。") // return //} //defer func() { @@ -121,7 +123,7 @@ func UploadManualServerBinary(c *gin.Context) { // //info, err := service.UploadManualServerBinary(c.Request.Context(), fileHeader.Filename, file) //if err != nil { - // respondFailure(c, err.Error()) + // response.RespondFailure(c, err.Error()) // return //} // @@ -130,7 +132,7 @@ func UploadManualServerBinary(c *gin.Context) { // message = "已完成上传并检查升级包版本。" //} // - //respondSuccessWithExtras(c, info, gin.H{ + //response.RespondSuccessWithExtras(c, info, gin.H{ // "message": message, //}) } @@ -143,21 +145,21 @@ func UploadManualServerBinary(c *gin.Context) { // @Success 200 {object} map[string]interface{} // @Router /api/update/manual-upgrade [post] func ConfirmManualServerUpgrade(c *gin.Context) { - respondFailure(c, "手动升级功能已禁用") + response.RespondFailure(c, "手动升级功能已禁用") return // //var request confirmManualUpgradeRequest - //if !bindJSON(c, &request) { + //if !bind.JSON(c, &request) { // return //} // //info, err := service.ConfirmManualServerUpgrade(request.UploadToken) //if err != nil { - // respondFailure(c, err.Error()) + // response.RespondFailure(c, err.Error()) // return //} // - //respondSuccessWithExtras(c, info, gin.H{ + //response.RespondSuccessWithExtras(c, info, gin.H{ // "message": "服务升级任务已启动,确认无误后将自动重启。", //}) } diff --git a/openflare_server/controller/uptimekuma.go b/openflare_server/controller/uptimekuma.go index ed3aa858..737be24a 100644 --- a/openflare_server/controller/uptimekuma.go +++ b/openflare_server/controller/uptimekuma.go @@ -1,6 +1,7 @@ package controller import ( + "openflare/common/response" "openflare/service" "github.com/gin-gonic/gin" @@ -17,8 +18,8 @@ import ( func SyncUptimeKuma(c *gin.Context) { err := service.SyncToUptimeKuma() if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccessMessage(c, "同步成功") + response.RespondSuccessMessage(c, "同步成功") } diff --git a/openflare_server/controller/user.go b/openflare_server/controller/user.go index fe02e45c..fa5d2e90 100644 --- a/openflare_server/controller/user.go +++ b/openflare_server/controller/user.go @@ -2,6 +2,8 @@ package controller import ( "openflare/common" + "openflare/common/response" + "openflare/controller/bind" "openflare/middleware" "openflare/model" "openflare/utils/security" @@ -18,17 +20,17 @@ type LoginRequest struct { func Login(c *gin.Context) { if !common.PasswordLoginEnabled { - respondFailure(c, "管理员关闭了密码登录") + response.RespondFailure(c, "管理员关闭了密码登录") return } var loginRequest LoginRequest - if !bindJSON(c, &loginRequest) { + if !bind.JSON(c, &loginRequest) { return } username := loginRequest.Username password := loginRequest.Password if username == "" || password == "" { - respondFailure(c, "无效的参数") + response.RespondFailure(c, "无效的参数") return } user := model.User{ @@ -37,7 +39,7 @@ func Login(c *gin.Context) { } err := user.ValidateAndFill() if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } setupLogin(&user, c) @@ -68,10 +70,10 @@ func setLoginToken(user *model.User) (*model.User, error) { func setupLogin(user *model.User, c *gin.Context) { cleanUser, err := setLoginToken(user) if err != nil { - respondFailure(c, "无法保存会话信息,请重试") + response.RespondFailure(c, "无法保存会话信息,请重试") return } - respondSuccess(c, *cleanUser) + response.RespondSuccess(c, *cleanUser) } func Logout(c *gin.Context) { @@ -80,12 +82,12 @@ func Logout(c *gin.Context) { user := model.ValidateUserToken(token) if user != nil && user.Id != 0 { if err := model.DB.Model(user).Update("token", "").Error; err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } } } - respondSuccessMessage(c, "") + response.RespondSuccessMessage(c, "") } func currentUserFromOpenFlareToken(c *gin.Context) *model.User { @@ -97,7 +99,7 @@ func currentUserFromOpenFlareToken(c *gin.Context) *model.User { } func Register(c *gin.Context) { - respondFailure(c, "非法请求") + response.RespondFailure(c, "非法请求") } func GetAllUsers(c *gin.Context) { @@ -107,99 +109,99 @@ func GetAllUsers(c *gin.Context) { } users, err := model.GetAllUsers(p*common.ItemsPerPage, common.ItemsPerPage) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, users) + response.RespondSuccess(c, users) } func SearchUsers(c *gin.Context) { keyword := c.Query("keyword") users, err := model.SearchUsers(keyword) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, users) + response.RespondSuccess(c, users) } func GetUser(c *gin.Context) { - id, ok := parseIDParam(c) + id, ok := bind.IDParam(c) if !ok { return } user, err := model.GetUserById(int(id), false) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } myRole := c.GetInt("role") if myRole <= user.Role { - respondFailure(c, "无权获取同级或更高等级用户的信息") + response.RespondFailure(c, "无权获取同级或更高等级用户的信息") return } - respondSuccess(c, user) + response.RespondSuccess(c, user) } func GenerateToken(c *gin.Context) { id := c.GetInt("id") user, err := model.GetUserById(id, true) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } // Generate a fresh JWT for the user tokenString, _, err := middleware.JWTMiddleware.TokenGenerator(user) if err != nil { - respondFailure(c, "生成 Token 失败: "+err.Error()) + response.RespondFailure(c, "生成 Token 失败: "+err.Error()) return } user.Token = tokenString if err := user.Update(false); err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, user.Token) + response.RespondSuccess(c, user.Token) } func GetSelf(c *gin.Context) { id := c.GetInt("id") user, err := model.GetUserById(id, false) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, user) + response.RespondSuccess(c, user) } func UpdateUser(c *gin.Context) { var updatedUser model.User - if !bindJSON(c, &updatedUser) { + if !bind.JSON(c, &updatedUser) { return } if updatedUser.Id == 0 { - respondFailure(c, "无效的参数") + response.RespondFailure(c, "无效的参数") return } if updatedUser.Password == "" { updatedUser.Password = "$I_LOVE_U" // make Validator happy :) } if err := validation.Validate.Struct(&updatedUser); err != nil { - respondFailure(c, "输入不合法 "+err.Error()) + response.RespondFailure(c, "输入不合法 "+err.Error()) return } originUser, err := model.GetUserById(updatedUser.Id, false) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } myRole := c.GetInt("role") if myRole <= originUser.Role { - respondFailure(c, "无权更新同权限等级或更高权限等级的用户信息") + response.RespondFailure(c, "无权更新同权限等级或更高权限等级的用户信息") return } if myRole <= updatedUser.Role { - respondFailure(c, "无权将其他用户权限等级提升到大于等于自己的权限等级") + response.RespondFailure(c, "无权将其他用户权限等级提升到大于等于自己的权限等级") return } if updatedUser.Password == "$I_LOVE_U" { @@ -207,22 +209,22 @@ func UpdateUser(c *gin.Context) { } updatePassword := updatedUser.Password != "" if err := updatedUser.Update(updatePassword); err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccessMessage(c, "") + response.RespondSuccessMessage(c, "") } func UpdateSelf(c *gin.Context) { var user model.User - if !bindJSON(c, &user) { + if !bind.JSON(c, &user) { return } if user.Password == "" { user.Password = "$I_LOVE_U" // make Validator happy :) } if err := validation.Validate.Struct(&user); err != nil { - respondFailure(c, "输入不合法 "+err.Error()) + response.RespondFailure(c, "输入不合法 "+err.Error()) return } @@ -238,53 +240,53 @@ func UpdateSelf(c *gin.Context) { } updatePassword := user.Password != "" if err := cleanUser.Update(updatePassword); err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccessMessage(c, "") + response.RespondSuccessMessage(c, "") } func DeleteUser(c *gin.Context) { - id, ok := parseIDParam(c) + id, ok := bind.IDParam(c) if !ok { return } originUser, err := model.GetUserById(int(id), false) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } myRole := c.GetInt("role") if myRole <= originUser.Role { - respondFailure(c, "无权删除同权限等级或更高权限等级的用户") + response.RespondFailure(c, "无权删除同权限等级或更高权限等级的用户") return } err = model.DeleteUserById(int(id)) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccessMessage(c, "") + response.RespondSuccessMessage(c, "") } func DeleteSelf(c *gin.Context) { id := c.GetInt("id") err := model.DeleteUserById(id) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccessMessage(c, "") + response.RespondSuccessMessage(c, "") } func CreateUser(c *gin.Context) { var user model.User - if !bindJSON(c, &user) { + if !bind.JSON(c, &user) { return } if user.Username == "" || user.Password == "" { - respondFailure(c, "无效的参数") + response.RespondFailure(c, "无效的参数") return } if user.DisplayName == "" { @@ -292,7 +294,7 @@ func CreateUser(c *gin.Context) { } myRole := c.GetInt("role") if user.Role >= myRole { - respondFailure(c, "无法创建权限大于等于自己的用户") + response.RespondFailure(c, "无法创建权限大于等于自己的用户") return } // Even for admin users, we cannot fully trust them! @@ -302,11 +304,11 @@ func CreateUser(c *gin.Context) { DisplayName: user.DisplayName, } if err := cleanUser.Insert(); err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccessMessage(c, "") + response.RespondSuccessMessage(c, "") } type ManageRequest struct { @@ -317,7 +319,7 @@ type ManageRequest struct { // ManageUser Only admin user can do this func ManageUser(c *gin.Context) { var req ManageRequest - if !bindJSON(c, &req) { + if !bind.JSON(c, &req) { return } user := model.User{ @@ -326,70 +328,70 @@ func ManageUser(c *gin.Context) { // Fill attributes model.DB.Where(&user).First(&user) if user.Id == 0 { - respondFailure(c, "用户不存在") + response.RespondFailure(c, "用户不存在") return } myRole := c.GetInt("role") if myRole <= user.Role && myRole != common.RoleRootUser { - respondFailure(c, "无权更新同权限等级或更高权限等级的用户信息") + response.RespondFailure(c, "无权更新同权限等级或更高权限等级的用户信息") return } switch req.Action { case "disable": user.Status = common.UserStatusDisabled if user.Role == common.RoleRootUser { - respondFailure(c, "无法禁用超级管理员用户") + response.RespondFailure(c, "无法禁用超级管理员用户") return } case "enable": user.Status = common.UserStatusEnabled case "delete": if user.Role == common.RoleRootUser { - respondFailure(c, "无法删除超级管理员用户") + response.RespondFailure(c, "无法删除超级管理员用户") return } if err := user.Delete(); err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } case "promote": if myRole != common.RoleRootUser { - respondFailure(c, "普通管理员用户无法提升其他用户为管理员") + response.RespondFailure(c, "普通管理员用户无法提升其他用户为管理员") return } if user.Role >= common.RoleAdminUser { - respondFailure(c, "该用户已经是管理员") + response.RespondFailure(c, "该用户已经是管理员") return } user.Role = common.RoleAdminUser case "demote": if user.Role == common.RoleRootUser { - respondFailure(c, "无法降级超级管理员用户") + response.RespondFailure(c, "无法降级超级管理员用户") return } if user.Role == common.RoleCommonUser { - respondFailure(c, "该用户已经是普通用户") + response.RespondFailure(c, "该用户已经是普通用户") return } user.Role = common.RoleCommonUser } if err := user.Update(false); err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } clearUser := model.User{ Role: user.Role, Status: user.Status, } - respondSuccess(c, clearUser) + response.RespondSuccess(c, clearUser) } func EmailBind(c *gin.Context) { email := c.Query("email") code := c.Query("code") if !security.VerifyCodeWithKey(email, code, security.EmailVerificationPurpose) { - respondFailure(c, "验证码错误或已过期") + response.RespondFailure(c, "验证码错误或已过期") return } id := c.GetInt("id") @@ -398,15 +400,15 @@ func EmailBind(c *gin.Context) { } err := user.FillUserById() if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } user.Email = email // no need to check if this email already taken, because we have used verification code to check it err = user.Update(false) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccessMessage(c, "") + response.RespondSuccessMessage(c, "") } diff --git a/openflare_server/controller/waf.go b/openflare_server/controller/waf.go index 976fc2d7..e0b0c536 100644 --- a/openflare_server/controller/waf.go +++ b/openflare_server/controller/waf.go @@ -1,6 +1,8 @@ package controller import ( + "openflare/common/response" + "openflare/controller/bind" "openflare/service" "strconv" @@ -14,82 +16,82 @@ type wafIDsRequest struct { func ListWAFRuleGroups(c *gin.Context) { groups, err := service.ListWAFRuleGroups() if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, groups) + response.RespondSuccess(c, groups) } func GetWAFRuleGroup(c *gin.Context) { - id, ok := parseIDParam(c) + id, ok := bind.IDParam(c) if !ok { return } group, err := service.GetWAFRuleGroup(id) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, group) + response.RespondSuccess(c, group) } func CreateWAFRuleGroup(c *gin.Context) { var input service.WAFRuleGroupInput - if !bindJSON(c, &input) { + if !bind.JSON(c, &input) { return } group, err := service.CreateWAFRuleGroup(input) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, group) + response.RespondSuccess(c, group) } func UpdateWAFRuleGroup(c *gin.Context) { - id, ok := parseIDParam(c) + id, ok := bind.IDParam(c) if !ok { return } var input service.WAFRuleGroupInput - if !bindJSON(c, &input) { + if !bind.JSON(c, &input) { return } group, err := service.UpdateWAFRuleGroup(id, input) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, group) + response.RespondSuccess(c, group) } func DeleteWAFRuleGroup(c *gin.Context) { - id, ok := parseIDParam(c) + id, ok := bind.IDParam(c) if !ok { return } if err := service.DeleteWAFRuleGroup(id); err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccessMessage(c, "") + response.RespondSuccessMessage(c, "") } func ReplaceWAFRuleGroupSites(c *gin.Context) { - id, ok := parseIDParam(c) + id, ok := bind.IDParam(c) if !ok { return } var request wafIDsRequest - if !bindJSON(c, &request) { + if !bind.JSON(c, &request) { return } group, err := service.ReplaceWAFRuleGroupSites(id, request.IDs) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, group) + response.RespondSuccess(c, group) } func GetWAFSiteRuleGroups(c *gin.Context) { @@ -99,10 +101,10 @@ func GetWAFSiteRuleGroups(c *gin.Context) { } view, err := service.GetWAFSiteRuleGroups(routeID) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, view) + response.RespondSuccess(c, view) } func ReplaceWAFSiteRuleGroups(c *gin.Context) { @@ -111,111 +113,111 @@ func ReplaceWAFSiteRuleGroups(c *gin.Context) { return } var request wafIDsRequest - if !bindJSON(c, &request) { + if !bind.JSON(c, &request) { return } view, err := service.ReplaceWAFSiteRuleGroups(routeID, request.IDs) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, view) + response.RespondSuccess(c, view) } func ListWAFIPGroups(c *gin.Context) { groups, err := service.ListWAFIPGroups() if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, groups) + response.RespondSuccess(c, groups) } func GetWAFIPGroup(c *gin.Context) { - id, ok := parseIDParam(c) + id, ok := bind.IDParam(c) if !ok { return } group, err := service.GetWAFIPGroup(id) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, group) + response.RespondSuccess(c, group) } func CreateWAFIPGroup(c *gin.Context) { var input service.WAFIPGroupInput - if !bindJSON(c, &input) { + if !bind.JSON(c, &input) { return } group, err := service.CreateWAFIPGroup(input) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, group) + response.RespondSuccess(c, group) } func UpdateWAFIPGroup(c *gin.Context) { - id, ok := parseIDParam(c) + id, ok := bind.IDParam(c) if !ok { return } var input service.WAFIPGroupInput - if !bindJSON(c, &input) { + if !bind.JSON(c, &input) { return } group, err := service.UpdateWAFIPGroup(id, input) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, group) + response.RespondSuccess(c, group) } func DeleteWAFIPGroup(c *gin.Context) { - id, ok := parseIDParam(c) + id, ok := bind.IDParam(c) if !ok { return } if err := service.DeleteWAFIPGroup(id); err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccessMessage(c, "") + response.RespondSuccessMessage(c, "") } func SyncWAFIPGroup(c *gin.Context) { - id, ok := parseIDParam(c) + id, ok := bind.IDParam(c) if !ok { return } result, err := service.SyncWAFIPGroup(id) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, result) + response.RespondSuccess(c, result) } func TestWAFIPGroupAutoConfig(c *gin.Context) { var input service.WAFIPGroupAutoTestInput - if !bindJSON(c, &input) { + if !bind.JSON(c, &input) { return } result, err := service.TestWAFIPGroupAutoConfig(input) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccess(c, result) + response.RespondSuccess(c, result) } func parseUintPathParam(c *gin.Context, name string) (uint, bool) { id, err := strconv.ParseUint(c.Param(name), 10, 64) if err != nil || id == 0 { - respondBadRequest(c, "invalid id") + response.RespondBadRequest(c, "invalid id") return 0, false } return uint(id), true diff --git a/openflare_server/controller/wechat.go b/openflare_server/controller/wechat.go index 1b5a97a7..08611d38 100644 --- a/openflare_server/controller/wechat.go +++ b/openflare_server/controller/wechat.go @@ -8,6 +8,7 @@ import ( "log/slog" "net/http" "openflare/common" + "openflare/common/response" "openflare/model" "time" @@ -58,13 +59,13 @@ func getWeChatIdByCode(code string) (string, error) { func WeChatAuth(c *gin.Context) { if !common.WeChatAuthEnabled { - respondFailure(c, "管理员未开启通过微信登录以及注册") + response.RespondFailure(c, "管理员未开启通过微信登录以及注册") return } code := c.Query("code") wechatId, err := getWeChatIdByCode(code) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } user := model.User{ @@ -73,16 +74,16 @@ func WeChatAuth(c *gin.Context) { if model.IsWeChatIdAlreadyTaken(wechatId) { err := user.FillUserByWeChatId() if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } } else { - respondFailure(c, "管理员关闭了新用户注册") + response.RespondFailure(c, "管理员关闭了新用户注册") return } if user.Status != common.UserStatusEnabled { - respondFailure(c, "用户已被封禁") + response.RespondFailure(c, "用户已被封禁") return } setupLogin(&user, c) @@ -90,17 +91,17 @@ func WeChatAuth(c *gin.Context) { func WeChatBind(c *gin.Context) { if !common.WeChatAuthEnabled { - respondFailure(c, "管理员未开启通过微信登录以及注册") + response.RespondFailure(c, "管理员未开启通过微信登录以及注册") return } code := c.Query("code") wechatId, err := getWeChatIdByCode(code) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } if model.IsWeChatIdAlreadyTaken(wechatId) { - respondFailure(c, "该微信账号已被绑定") + response.RespondFailure(c, "该微信账号已被绑定") return } id := c.GetInt("id") @@ -109,15 +110,15 @@ func WeChatBind(c *gin.Context) { } err = user.FillUserById() if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } user.WeChatId = wechatId err = user.Update(false) if err != nil { - respondFailure(c, err.Error()) + response.RespondFailure(c, err.Error()) return } - respondSuccessMessage(c, "") + response.RespondSuccessMessage(c, "") return }