mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-09-29 14:06:36 +08:00
[优化] response 结构调整
This commit is contained in:
@@ -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 白名单调整为准入名单语义:存在白名单规则时,未命中白名单的请求会被拦截
|
||||
|
||||
@@ -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/...
|
||||
```
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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": "清理成功",
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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, "")
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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": "服务升级任务已启动,确认无误后将自动重启。",
|
||||
//})
|
||||
}
|
||||
|
||||
@@ -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, "同步成功")
|
||||
}
|
||||
|
||||
@@ -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, "")
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user