| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240 |
- package main
- import (
- "fmt"
- "os"
- "strings"
- )
- type permDecl struct {
- Code string
- Name string
- }
- type routePermDecl struct {
- Method string
- Path string
- PermCode string
- DataCode string
- }
- type fieldNode struct {
- Fields map[string]string
- Nested map[string]*fieldNode
- }
- type collectResult struct {
- perms []permDecl
- routePerms []routePermDecl
- fieldPerms map[string]*fieldPermMap // "METHOD /path" → fieldPermMap
- }
- type fieldPermMap struct {
- Request *fieldNode
- Response *fieldNode
- }
- func collect(input *PluginInput) *collectResult {
- seen := make(map[string]bool)
- result := &collectResult{
- fieldPerms: make(map[string]*fieldPermMap),
- }
- if input == nil || input.Api == nil {
- return result
- }
- // 建立类型名 → TypeDef 的索引,用于展开嵌套类型
- typeIndex := make(map[string]*TypeDef, len(input.Api.Types))
- for i := range input.Api.Types {
- typeIndex[input.Api.Types[i].RawName] = &input.Api.Types[i]
- }
- addPerm := func(code, name string) {
- if seen[code] || code == "" {
- return
- }
- seen[code] = true
- if name == "" {
- name = generatePermName(code)
- }
- result.perms = append(result.perms, permDecl{Code: code, Name: name})
- }
- for _, group := range input.Api.Service.Groups {
- for _, route := range group.Routes {
- method := strings.ToUpper(route.Method)
- path := route.Path
- key := method + " " + path
- permCode := ""
- permName := ""
- if route.AtDoc.Properties != nil {
- permCode = route.AtDoc.Properties["perm"]
- permName = route.AtDoc.Properties["summary"]
- }
- if permCode == "" {
- fmt.Fprintf(os.Stderr, "WARN: handler %s (%s %s) has no perm declaration, treated as public\n",
- route.Handler, method, path)
- continue
- }
- addPerm(permCode, permName)
- dataCode := apiToDataCode(permCode)
- if dataCode != "" {
- addPerm(dataCode, permName)
- }
- result.routePerms = append(result.routePerms, routePermDecl{
- Method: method,
- Path: path,
- PermCode: permCode,
- DataCode: dataCode,
- })
- var reqNode *fieldNode
- if route.RequestType != nil {
- reqNode = collectFieldPerms(route.RequestType.Members, typeIndex)
- collectPermCodes(reqNode, addPerm)
- }
- var respNode *fieldNode
- if route.ResponseType != nil {
- respNode = collectFieldPerms(route.ResponseType.Members, typeIndex)
- collectPermCodes(respNode, addPerm)
- }
- if reqNode != nil || respNode != nil {
- result.fieldPerms[key] = &fieldPermMap{
- Request: reqNode,
- Response: respNode,
- }
- }
- }
- }
- return result
- }
- // collectFieldPerms 递归构建 fieldNode 树
- func collectFieldPerms(members []Member, typeIndex map[string]*TypeDef) *fieldNode {
- node := &fieldNode{
- Fields: make(map[string]string),
- Nested: make(map[string]*fieldNode),
- }
- for _, m := range members {
- jsonName := extractTagValue(m.Tag, "json")
- if jsonName == "" {
- jsonName = m.Name
- }
- permCode := extractTagValue(m.Tag, "perm")
- if permCode != "" {
- node.Fields[jsonName] = permCode
- }
- rawName := strings.TrimPrefix(m.Type.RawName, "[]")
- if nested, ok := typeIndex[rawName]; ok && len(nested.Members) > 0 {
- child := collectFieldPerms(nested.Members, typeIndex)
- if len(child.Fields) > 0 || len(child.Nested) > 0 {
- node.Nested[jsonName] = child
- }
- }
- }
- if len(node.Fields) == 0 && len(node.Nested) == 0 {
- return nil
- }
- return node
- }
- // collectPermCodes 从 fieldNode 树中提取所有 permCode 并注册
- func collectPermCodes(node *fieldNode, addPerm func(string, string)) {
- if node == nil {
- return
- }
- for _, code := range node.Fields {
- addPerm(code, "")
- }
- for _, child := range node.Nested {
- collectPermCodes(child, addPerm)
- }
- }
- // extractTagValue 从 struct tag 字符串中提取指定 key 的值
- // tag 格式:`json:"username" perm:"data:user:email:write"`
- func extractTagValue(tag, key string) string {
- tag = strings.Trim(tag, "`")
- search := key + `:"`
- idx := strings.Index(tag, search)
- if idx == -1 {
- return ""
- }
- rest := tag[idx+len(search):]
- end := strings.Index(rest, `"`)
- if end == -1 {
- return ""
- }
- val := rest[:end]
- // 取 json tag 的第一段(去掉 omitempty 等)
- if key == "json" {
- val = strings.Split(val, ",")[0]
- if val == "-" {
- return ""
- }
- }
- return val
- }
- func apiToDataCode(apiCode string) string {
- if !strings.HasPrefix(apiCode, "api:") {
- return ""
- }
- return "data:" + apiCode[4:]
- }
- func generatePermName(code string) string {
- parts := strings.Split(code, ":")
- if len(parts) < 2 {
- return code
- }
- actionMap := map[string]string{
- "read": "读取",
- "write": "写入",
- "create": "创建",
- "update": "更新",
- "delete": "删除",
- "list": "列表",
- "detail": "详情",
- }
- capitalize := func(s string) string {
- if len(s) == 0 {
- return s
- }
- return strings.ToUpper(s[:1]) + s[1:]
- }
- // 字段权限:data:model:field:read|write → "{Model} {field} 字段 [读取|写入]"
- if parts[0] == "data" && len(parts) == 4 {
- action := actionMap[parts[3]]
- if action == "" {
- action = parts[3]
- }
- return capitalize(parts[1]) + " " + parts[2] + "字段 " + action
- }
- // 接口/数据权限:api:model:action 或 data:model:action
- var result []string
- for i := 1; i < len(parts); i++ {
- p := parts[i]
- if mapped, ok := actionMap[p]; ok {
- result = append(result, mapped)
- } else {
- result = append(result, capitalize(p))
- }
- }
- return strings.Join(result, " ")
- }
|