补全权限数据 & 优化 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 语句,确保脚本可以幂等执行
|
||||
- 编写 create table 语句,按需添加审计字段和软删除字段 (created_at, updated_at, deleted_at)
|
||||
- 为有必要的字段添加索引
|
||||
- 为数据表及其字段添加注释
|
||||
- 在文件末尾创建数据表流程全部结束后,为字段添加外键
|
||||
2. 建议用数据库工具检查差异并增量更新,或者手动增量更新
|
||||
3. 创建 model 文件,并将其添加到 gen 代码中
|
||||
4. 生成查询文件
|
||||
4. 调用 `go run ./cmd/gen/main.go` 生成查询文件
|
||||
|
||||
### 权限管理
|
||||
### 更新数据表流程
|
||||
|
||||
在 `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
|
||||
((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 子权限
|
||||
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);
|
||||
@@ -285,6 +289,10 @@ 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);
|
||||
|
||||
-- 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
|
||||
-- --------------------------
|
||||
|
||||
@@ -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) {
|
||||
api := app.Group("/api")
|
||||
publicRouter(api)
|
||||
clientRouter(api)
|
||||
userRouter(api)
|
||||
adminRouter(api)
|
||||
clientRouter(api)
|
||||
|
||||
// 回调
|
||||
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.Get("/authorize", auth2.AuthorizeGet)
|
||||
@@ -62,6 +63,48 @@ func userRouter(api fiber.Router) {
|
||||
auth.Post("/revoke", auth2.Revoke)
|
||||
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.Post("/update", handlers.UpdateUser)
|
||||
@@ -102,7 +145,6 @@ func userRouter(api fiber.Router) {
|
||||
trade.Post("/create", handlers.TradeCreate)
|
||||
trade.Post("/complete", handlers.TradeComplete)
|
||||
trade.Post("/cancel", handlers.TradeCancel)
|
||||
trade.Get("/check", handlers.TradeCheck)
|
||||
|
||||
// 账单
|
||||
bill := api.Group("/bill")
|
||||
@@ -121,51 +163,11 @@ func userRouter(api fiber.Router) {
|
||||
announcement := api.Group("/announcement")
|
||||
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.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) {
|
||||
api = api.Group("/admin")
|
||||
|
||||
Reference in New Issue
Block a user