| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226 |
- 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 fieldPermMap struct {
- Request map[string]string // json字段名 → permCode
- Response map[string]string // json字段名 → permCode
- }
- type collectResult struct {
- perms []permDecl
- routePerms []routePermDecl
- fieldPerms map[string]fieldPermMap // "METHOD /path" → fieldPermMap
- }
- 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,
- })
- fm := fieldPermMap{
- Request: make(map[string]string),
- Response: make(map[string]string),
- }
- if route.RequestType != nil {
- for jsonField, permTag := range extractFieldPermsDeep(route.RequestType, typeIndex) {
- fm.Request[jsonField] = permTag
- addPerm(permTag, "")
- }
- }
- if route.ResponseType != nil {
- for jsonField, permTag := range extractFieldPermsDeep(route.ResponseType, typeIndex) {
- fm.Response[jsonField] = permTag
- addPerm(permTag, "")
- }
- }
- if len(fm.Request) > 0 || len(fm.Response) > 0 {
- result.fieldPerms[key] = fm
- }
- }
- }
- return result
- }
- // extractFieldPermsDeep 递归展开嵌套类型,提取所有 perm tag
- func extractFieldPermsDeep(t *TypeDef, typeIndex map[string]*TypeDef) map[string]string {
- result := make(map[string]string)
- if t == nil {
- return result
- }
- collectFieldPerms(t.Members, typeIndex, result)
- return result
- }
- func collectFieldPerms(members []Member, typeIndex map[string]*TypeDef, result map[string]string) {
- for _, m := range members {
- jsonName := extractTagValue(m.Tag, "json")
- if jsonName == "" {
- jsonName = m.Name
- }
- permCode := extractTagValue(m.Tag, "perm")
- if permCode != "" {
- result[jsonName] = permCode
- continue
- }
- // 没有 perm tag,尝试展开嵌套类型(去掉 [] 前缀)
- rawName := strings.TrimPrefix(m.Type.RawName, "[]")
- if nested, ok := typeIndex[rawName]; ok && len(nested.Members) > 0 {
- collectFieldPerms(nested.Members, typeIndex, result)
- }
- }
- }
- // 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, " ")
- }
|