补全权限数据 & 优化 router 代码结构
This commit is contained in:
29
README.md
29
README.md
@@ -7,6 +7,7 @@
|
|||||||
交易信息持久化
|
交易信息持久化
|
||||||
|
|
||||||
订单关闭问题,在前端关闭窗口后直接调用了全部订单接口,应改成先确认再关闭
|
订单关闭问题,在前端关闭窗口后直接调用了全部订单接口,应改成先确认再关闭
|
||||||
|
|
||||||
- 取消订单接口改成只允许管理员调用
|
- 取消订单接口改成只允许管理员调用
|
||||||
- 新增关闭订单接口,关闭订单的逻辑是先尝试完成,如果订单未支付则取消订单
|
- 新增关闭订单接口,关闭订单的逻辑是先尝试完成,如果订单未支付则取消订单
|
||||||
|
|
||||||
@@ -18,27 +19,33 @@
|
|||||||
|
|
||||||
冷数据迁移方案
|
冷数据迁移方案
|
||||||
|
|
||||||
## 开发环境
|
## 开发流程
|
||||||
|
|
||||||
### 更新表结构的流程
|
### 新建数据表流程
|
||||||
|
|
||||||
1. 编辑 `scripts/sql/init.sql` 文件,参照原有格式,需要注意:
|
1. 创建 model 文件
|
||||||
|
2. 将 model 按照格式添加声明到 `cmd/gen/main.go` 中
|
||||||
|
3. 编辑 `scripts/sql/init.sql` 文件,参照原有格式,需要注意:
|
||||||
- 先写 drop table if exists 语句,确保脚本可以幂等执行
|
- 先写 drop table if exists 语句,确保脚本可以幂等执行
|
||||||
- 编写 create table 语句,按需添加审计字段和软删除字段 (created_at, updated_at, deleted_at)
|
|
||||||
- 为有必要的字段添加索引
|
- 为有必要的字段添加索引
|
||||||
- 为数据表及其字段添加注释
|
- 为数据表及其字段添加注释
|
||||||
- 在文件末尾创建数据表流程全部结束后,为字段添加外键
|
- 在文件末尾创建数据表流程全部结束后,为字段添加外键
|
||||||
2. 建议用数据库工具检查差异并增量更新,或者手动增量更新
|
4. 调用 `go run ./cmd/gen/main.go` 生成查询文件
|
||||||
3. 创建 model 文件,并将其添加到 gen 代码中
|
|
||||||
4. 生成查询文件
|
|
||||||
|
|
||||||
### 权限管理
|
### 更新数据表流程
|
||||||
|
|
||||||
在 `web/core/scopes.go` 下定义了系统所有静态权限
|
1. 更新 model 文件
|
||||||
|
2. 编辑 `scripts/sql/init.sql` 文件,参照原有格式,需要注意:
|
||||||
|
- 先写 drop table if exists 语句,确保脚本可以幂等执行
|
||||||
|
- 为有必要的字段添加索引
|
||||||
|
- 为数据表及其字段添加注释
|
||||||
|
- 在文件末尾创建数据表流程全部结束后,为字段添加外键
|
||||||
|
3. 调用 `go run ./cmd/gen/main.go` 更新查询文件
|
||||||
|
|
||||||
新增系统权限需要在数据库中配套添加权限
|
### 新增接口或修改接口权限
|
||||||
|
|
||||||
前端也需要新增配套权限定义
|
1. 在 `web/core/scopes.go` 下声明权限常量。通常格式为 `Model:Action:SubAction`,例如 `User:Create`、`User:Delete`、`User:Update:Password` 等
|
||||||
|
2. 在 `scripts/sql/fill.sql` 文件的权限区域添加或修改权限条目
|
||||||
|
|
||||||
## 业务逻辑
|
## 业务逻辑
|
||||||
|
|
||||||
|
|||||||
@@ -239,6 +239,10 @@ insert into permission (parent_id, name, description, sort) values
|
|||||||
insert into permission (parent_id, name, description, sort) values
|
insert into permission (parent_id, name, description, sort) values
|
||||||
((select id from permission where name = 'proxy:write' and deleted_at is null), 'proxy:write:status', '更改代理状态', 1);
|
((select id from permission where name = 'proxy:write' and deleted_at is null), 'proxy:write:status', '更改代理状态', 1);
|
||||||
|
|
||||||
|
-- channel:write 子权限
|
||||||
|
insert into permission (parent_id, name, description, sort) values
|
||||||
|
((select id from permission where name = 'channel:write' and deleted_at is null), 'channel:write:clear_expired', '清理过期 IP', 1);
|
||||||
|
|
||||||
-- resource:short 子权限
|
-- resource:short 子权限
|
||||||
insert into permission (parent_id, name, description, sort) values
|
insert into permission (parent_id, name, description, sort) values
|
||||||
((select id from permission where name = 'resource:short' and deleted_at is null), 'resource:short:read', '读取用户短效动态套餐列表', 1);
|
((select id from permission where name = 'resource:short' and deleted_at is null), 'resource:short:read', '读取用户短效动态套餐列表', 1);
|
||||||
@@ -285,6 +289,10 @@ insert into permission (parent_id, name, description, sort) values
|
|||||||
insert into permission (parent_id, name, description, sort) values
|
insert into permission (parent_id, name, description, sort) values
|
||||||
((select id from permission where name = 'coupon_user:read' and deleted_at is null), 'coupon_user:read:of_user', '读取指定用户的已发放优惠券列表', 1);
|
((select id from permission where name = 'coupon_user:read' and deleted_at is null), 'coupon_user:read:of_user', '读取指定用户的已发放优惠券列表', 1);
|
||||||
|
|
||||||
|
-- trade:write 子权限
|
||||||
|
insert into permission (parent_id, name, description, sort) values
|
||||||
|
((select id from permission where name = 'trade:write' and deleted_at is null), 'trade:write:complete', '完成交易', 1);
|
||||||
|
|
||||||
-- --------------------------
|
-- --------------------------
|
||||||
-- level 4
|
-- level 4
|
||||||
-- --------------------------
|
-- --------------------------
|
||||||
|
|||||||
@@ -1,149 +0,0 @@
|
|||||||
package handlers
|
|
||||||
|
|
||||||
import (
|
|
||||||
s "platform/web/services"
|
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
|
||||||
)
|
|
||||||
|
|
||||||
type RegisterEdgeReq struct {
|
|
||||||
Name string `json:"name" validate:"required"`
|
|
||||||
Version int `json:"version" validate:"required"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type RegisterEdgeResp struct {
|
|
||||||
Id int32 `json:"id"`
|
|
||||||
Host string `json:"host"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func AssignEdge(c *fiber.Ctx) (err error) {
|
|
||||||
return c.JSON(map[string]any{
|
|
||||||
"error": "接口暂不可用",
|
|
||||||
})
|
|
||||||
// // 验证请求参数
|
|
||||||
// var req = new(RegisterEdgeReq)
|
|
||||||
// err = g.Validator.Validate(c, req)
|
|
||||||
// if err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // 全局锁,防止并发注册
|
|
||||||
// var mutex = g.Redsync.NewMutex("edge:discovery")
|
|
||||||
// if err := mutex.Lock(); err != nil {
|
|
||||||
// return errors.New("服务繁忙,请稍后重试")
|
|
||||||
// }
|
|
||||||
// defer func() {
|
|
||||||
// if ok, err := mutex.Unlock(); err != nil {
|
|
||||||
// slog.Error("解锁失败", slog.Bool("ok", ok), slog.Any("err", err))
|
|
||||||
// }
|
|
||||||
// }()
|
|
||||||
|
|
||||||
// // 检查节点
|
|
||||||
// var fwd *m.Proxy
|
|
||||||
// var edge *m.Edge
|
|
||||||
// edge, err = q.Edge.
|
|
||||||
// Where(q.Edge.Mac.Eq(req.Name)).
|
|
||||||
// Take()
|
|
||||||
// if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
||||||
// // 挑选合适的转发服务
|
|
||||||
// fwd, err = q.Proxy.
|
|
||||||
// LeftJoin(q.Edge, q.Edge.ProxyID.EqCol(q.Proxy.ID), q.Edge.Status.Eq(1)).
|
|
||||||
// Select(q.Proxy.ALL, q.Edge.ALL.Count().As("count")).
|
|
||||||
// Where(q.Proxy.Type.Eq(int32(proxy2.TypeSelfHosted))).
|
|
||||||
// Group(q.Proxy.ID).
|
|
||||||
// Order(field.NewField("", "count").Desc()).
|
|
||||||
// First()
|
|
||||||
// if err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
// // 保存节点信息
|
|
||||||
// edge = &m.Edge{
|
|
||||||
// Name: req.Name,
|
|
||||||
// Version: int32(req.Version),
|
|
||||||
// Type: int32(edge2.TypeSelfHosted),
|
|
||||||
// ProxyID: &fwd.ID,
|
|
||||||
// }
|
|
||||||
// err = q.Edge.Create(edge)
|
|
||||||
// if err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
// } else if err == nil {
|
|
||||||
// // 获取已配置的转发服务
|
|
||||||
// fwd, err = q.Proxy.
|
|
||||||
// Where(q.Proxy.ID.Eq(*edge.ProxyID)).
|
|
||||||
// Take()
|
|
||||||
// if err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
// // 节点已存在,更新版本号
|
|
||||||
// if edge.Version < int32(req.Version) {
|
|
||||||
// _, err = q.Edge.
|
|
||||||
// Where(q.Edge.ID.Eq(edge.ID)).
|
|
||||||
// UpdateSimple(q.Edge.Version.Value(int32(req.Version)))
|
|
||||||
// if err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // 返回服务地址
|
|
||||||
// return c.JSON(RegisterEdgeResp{
|
|
||||||
// Id: edge.ID,
|
|
||||||
// Host: fwd.Host,
|
|
||||||
// })
|
|
||||||
}
|
|
||||||
|
|
||||||
type AllEdgesAvailableReq struct {
|
|
||||||
s.EdgeFilter
|
|
||||||
Count int `json:"count"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type AllEdgesAvailableRespItem struct {
|
|
||||||
Ip string `json:"ip"` // 节点地址
|
|
||||||
Port int32 `json:"port"` // 代理服务端口
|
|
||||||
Isp string `json:"isp"` // 运营商
|
|
||||||
Prov string `json:"prov"` // 省份
|
|
||||||
City string `json:"city"` // 城市
|
|
||||||
Status int32 `json:"status"` // 节点状态:0-离线,1-正常
|
|
||||||
}
|
|
||||||
|
|
||||||
func AllEdgesAvailable(c *fiber.Ctx) (err error) {
|
|
||||||
return c.JSON(map[string]any{
|
|
||||||
"error": "接口暂不可用",
|
|
||||||
})
|
|
||||||
|
|
||||||
// // 检查权限
|
|
||||||
// _, err = auth.GetAuthCtx(c).PermitSecretClient()
|
|
||||||
// if err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // 验证请求参数
|
|
||||||
// var req = new(AllEdgesAvailableReq)
|
|
||||||
// err = g.Validator.Validate(c, req)
|
|
||||||
// if err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // 获取可用的转发服务
|
|
||||||
// infos, err := s.Edge.AllEdges(req.Count, req.EdgeFilter)
|
|
||||||
// if err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // 返回结果
|
|
||||||
// var edges = make([]AllEdgesAvailableRespItem, len(infos))
|
|
||||||
// for i, info := range infos {
|
|
||||||
// edges[i] = AllEdgesAvailableRespItem{
|
|
||||||
// Ip: info.Host,
|
|
||||||
// Port: u.Z(info.ProxyPort),
|
|
||||||
// Isp: edge2.ISP(info.Isp).String(),
|
|
||||||
// Prov: info.Prov,
|
|
||||||
// City: info.City,
|
|
||||||
// Status: info.Status,
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// return c.JSON(edges)
|
|
||||||
}
|
|
||||||
@@ -15,9 +15,10 @@ import (
|
|||||||
|
|
||||||
func ApplyRouters(app *fiber.App) {
|
func ApplyRouters(app *fiber.App) {
|
||||||
api := app.Group("/api")
|
api := app.Group("/api")
|
||||||
|
publicRouter(api)
|
||||||
|
clientRouter(api)
|
||||||
userRouter(api)
|
userRouter(api)
|
||||||
adminRouter(api)
|
adminRouter(api)
|
||||||
clientRouter(api)
|
|
||||||
|
|
||||||
// 回调
|
// 回调
|
||||||
callbacks := app.Group("/callback")
|
callbacks := app.Group("/callback")
|
||||||
@@ -52,8 +53,8 @@ func ApplyRouters(app *fiber.App) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 用户接口路由
|
// 公开接口路由
|
||||||
func userRouter(api fiber.Router) {
|
func publicRouter(api fiber.Router) {
|
||||||
// 认证
|
// 认证
|
||||||
auth := api.Group("/auth")
|
auth := api.Group("/auth")
|
||||||
auth.Get("/authorize", auth2.AuthorizeGet)
|
auth.Get("/authorize", auth2.AuthorizeGet)
|
||||||
@@ -62,6 +63,48 @@ func userRouter(api fiber.Router) {
|
|||||||
auth.Post("/revoke", auth2.Revoke)
|
auth.Post("/revoke", auth2.Revoke)
|
||||||
auth.Post("/introspect", auth2.Introspect)
|
auth.Post("/introspect", auth2.Introspect)
|
||||||
|
|
||||||
|
// 套餐
|
||||||
|
resource := api.Group("/resource")
|
||||||
|
resource.Post("/price", handlers.ResourcePrice)
|
||||||
|
|
||||||
|
// 交易
|
||||||
|
trade := api.Group("/trade")
|
||||||
|
trade.Get("/check", handlers.TradeCheck)
|
||||||
|
|
||||||
|
// 前台
|
||||||
|
inquiry := api.Group("/inquiry")
|
||||||
|
inquiry.Post("/create", handlers.CreateInquiry)
|
||||||
|
|
||||||
|
// 产品
|
||||||
|
product := api.Group("/product")
|
||||||
|
product.Post("/list", handlers.AllProduct)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 客户端接口路由
|
||||||
|
func clientRouter(api fiber.Router) {
|
||||||
|
client := api
|
||||||
|
|
||||||
|
// 验证短信令牌
|
||||||
|
client.Post("/verify/sms", handlers.SendSmsCode)
|
||||||
|
|
||||||
|
// 网关
|
||||||
|
proxy := client.Group("/proxy")
|
||||||
|
proxy.Post("/online", handlers.ProxyReportOnline)
|
||||||
|
proxy.Post("/offline", handlers.ProxyReportOffline)
|
||||||
|
proxy.Post("/update", handlers.ProxyReportUpdate)
|
||||||
|
|
||||||
|
// 通道管理
|
||||||
|
channel := client.Group("/channel")
|
||||||
|
channel.Post("/remove", handlers.RemoveChannels)
|
||||||
|
|
||||||
|
// 文章查看
|
||||||
|
article := api.Group("/article")
|
||||||
|
article.Post("/nav", handlers.NavArticle)
|
||||||
|
article.Post("/get", handlers.GetArticle)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户接口路由
|
||||||
|
func userRouter(api fiber.Router) {
|
||||||
// 用户
|
// 用户
|
||||||
user := api.Group("/user")
|
user := api.Group("/user")
|
||||||
user.Post("/update", handlers.UpdateUser)
|
user.Post("/update", handlers.UpdateUser)
|
||||||
@@ -102,7 +145,6 @@ func userRouter(api fiber.Router) {
|
|||||||
trade.Post("/create", handlers.TradeCreate)
|
trade.Post("/create", handlers.TradeCreate)
|
||||||
trade.Post("/complete", handlers.TradeComplete)
|
trade.Post("/complete", handlers.TradeComplete)
|
||||||
trade.Post("/cancel", handlers.TradeCancel)
|
trade.Post("/cancel", handlers.TradeCancel)
|
||||||
trade.Get("/check", handlers.TradeCheck)
|
|
||||||
|
|
||||||
// 账单
|
// 账单
|
||||||
bill := api.Group("/bill")
|
bill := api.Group("/bill")
|
||||||
@@ -121,51 +163,11 @@ func userRouter(api fiber.Router) {
|
|||||||
announcement := api.Group("/announcement")
|
announcement := api.Group("/announcement")
|
||||||
announcement.Post("/list", handlers.ListAnnouncements)
|
announcement.Post("/list", handlers.ListAnnouncements)
|
||||||
|
|
||||||
// 网关
|
|
||||||
proxy := api.Group("/proxy")
|
|
||||||
proxy.Post("/online", handlers.ProxyReportOnline)
|
|
||||||
proxy.Post("/offline", handlers.ProxyReportOffline)
|
|
||||||
proxy.Post("/update", handlers.ProxyReportUpdate)
|
|
||||||
|
|
||||||
// 节点
|
|
||||||
edge := api.Group("/edge")
|
|
||||||
edge.Post("/assign", handlers.AssignEdge)
|
|
||||||
edge.Post("/all", handlers.AllEdgesAvailable)
|
|
||||||
|
|
||||||
// 前台
|
|
||||||
inquiry := api.Group("/inquiry")
|
|
||||||
inquiry.Post("/create", handlers.CreateInquiry)
|
|
||||||
|
|
||||||
// 产品
|
|
||||||
product := api.Group("/product")
|
|
||||||
product.Post("/list", handlers.AllProduct)
|
|
||||||
|
|
||||||
// 认证
|
// 认证
|
||||||
verify := api.Group("/verify")
|
verify := api.Group("/verify")
|
||||||
verify.Post("/sms/password", handlers.SendSmsCodeForPassword)
|
verify.Post("/sms/password", handlers.SendSmsCodeForPassword)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 客户端接口路由
|
|
||||||
func clientRouter(api fiber.Router) {
|
|
||||||
client := api
|
|
||||||
|
|
||||||
// 验证短信令牌
|
|
||||||
client.Post("/verify/sms", handlers.SendSmsCode)
|
|
||||||
|
|
||||||
// 套餐定价查询
|
|
||||||
resource := client.Group("/resource")
|
|
||||||
resource.Post("/price", handlers.ResourcePrice)
|
|
||||||
|
|
||||||
// 通道管理
|
|
||||||
channel := client.Group("/channel")
|
|
||||||
channel.Post("/remove", handlers.RemoveChannels)
|
|
||||||
|
|
||||||
// 文章查看
|
|
||||||
article := api.Group("/article")
|
|
||||||
article.Post("/nav", handlers.NavArticle)
|
|
||||||
article.Post("/get", handlers.GetArticle)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 管理员接口路由
|
// 管理员接口路由
|
||||||
func adminRouter(api fiber.Router) {
|
func adminRouter(api fiber.Router) {
|
||||||
api = api.Group("/admin")
|
api = api.Group("/admin")
|
||||||
|
|||||||
Reference in New Issue
Block a user