122 lines
3.5 KiB
Go
122 lines
3.5 KiB
Go
|
|
package usecase
|
||
|
|
|
||
|
|
import (
|
||
|
|
"sort"
|
||
|
|
|
||
|
|
"gateway/internal/model/permission/domain/entity"
|
||
|
|
"gateway/internal/model/permission/domain/enum"
|
||
|
|
dom "gateway/internal/model/permission/domain/usecase"
|
||
|
|
)
|
||
|
|
|
||
|
|
// buildPermissionTree converts the flat permission list into a parent →
|
||
|
|
// children tree. Roots (parent == "") are returned in alphabetical order
|
||
|
|
// by Name for stable client rendering.
|
||
|
|
func buildPermissionTree(perms []*entity.Permission) []*dom.PermissionTreeNode {
|
||
|
|
byParent := make(map[string][]*dom.PermissionTreeNode)
|
||
|
|
indexByID := make(map[string]*dom.PermissionTreeNode, len(perms))
|
||
|
|
for _, perm := range perms {
|
||
|
|
node := permissionToNode(perm)
|
||
|
|
indexByID[node.ID] = node
|
||
|
|
byParent[perm.Parent] = append(byParent[perm.Parent], node)
|
||
|
|
}
|
||
|
|
for _, children := range byParent {
|
||
|
|
sort.SliceStable(children, func(i, j int) bool {
|
||
|
|
return children[i].Name < children[j].Name
|
||
|
|
})
|
||
|
|
}
|
||
|
|
for parentID, children := range byParent {
|
||
|
|
if parent, ok := indexByID[parentID]; ok {
|
||
|
|
parent.Children = children
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return byParent[""]
|
||
|
|
}
|
||
|
|
|
||
|
|
// filterOpenNodes prunes status=close subtrees (and any parent that has
|
||
|
|
// no remaining children). Mirrors permission-server's filterOpenNodes.
|
||
|
|
func filterOpenNodes(nodes []*dom.PermissionTreeNode) []*dom.PermissionTreeNode {
|
||
|
|
out := make([]*dom.PermissionTreeNode, 0, len(nodes))
|
||
|
|
for _, node := range nodes {
|
||
|
|
if node.Status != enum.StatusOpen {
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
if len(node.Children) > 0 {
|
||
|
|
node.Children = filterOpenNodes(node.Children)
|
||
|
|
}
|
||
|
|
out = append(out, node)
|
||
|
|
}
|
||
|
|
return out
|
||
|
|
}
|
||
|
|
|
||
|
|
// filterByType drops subtrees whose type does not match. Useful for the
|
||
|
|
// "frontend menu only" client query.
|
||
|
|
func filterByType(nodes []*dom.PermissionTreeNode, t enum.PermissionType) []*dom.PermissionTreeNode {
|
||
|
|
out := make([]*dom.PermissionTreeNode, 0, len(nodes))
|
||
|
|
for _, node := range nodes {
|
||
|
|
// Category nodes inherit the type of their children when they
|
||
|
|
// have no leaf type of their own; filter recursively first.
|
||
|
|
var kids []*dom.PermissionTreeNode
|
||
|
|
if len(node.Children) > 0 {
|
||
|
|
kids = filterByType(node.Children, t)
|
||
|
|
}
|
||
|
|
if node.Type == t || len(kids) > 0 {
|
||
|
|
node.Children = kids
|
||
|
|
out = append(out, node)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return out
|
||
|
|
}
|
||
|
|
|
||
|
|
// getFullParentPermissionIDs walks up the parent chain for each id in
|
||
|
|
// requestedIDs and returns the deduplicated closure (requested + every
|
||
|
|
// ancestor). Mirrors permission-server's helper of the same name; used
|
||
|
|
// when persisting RolePermissions so a tenant prefix-clicking a leaf also
|
||
|
|
// gets the parent UI sections.
|
||
|
|
func getFullParentPermissionIDs(
|
||
|
|
requestedIDs []string,
|
||
|
|
allPermissions []*entity.Permission,
|
||
|
|
) []string {
|
||
|
|
parentByID := make(map[string]string, len(allPermissions))
|
||
|
|
for _, perm := range allPermissions {
|
||
|
|
parentByID[perm.ID.Hex()] = perm.Parent
|
||
|
|
}
|
||
|
|
seen := make(map[string]struct{}, len(requestedIDs)*2)
|
||
|
|
out := make([]string, 0, len(requestedIDs)*2)
|
||
|
|
for _, id := range requestedIDs {
|
||
|
|
walkParents(id, parentByID, seen, &out)
|
||
|
|
}
|
||
|
|
return out
|
||
|
|
}
|
||
|
|
|
||
|
|
func walkParents(
|
||
|
|
id string,
|
||
|
|
parentByID map[string]string,
|
||
|
|
seen map[string]struct{},
|
||
|
|
out *[]string,
|
||
|
|
) {
|
||
|
|
for id != "" {
|
||
|
|
if _, ok := seen[id]; ok {
|
||
|
|
return
|
||
|
|
}
|
||
|
|
seen[id] = struct{}{}
|
||
|
|
*out = append(*out, id)
|
||
|
|
parent, ok := parentByID[id]
|
||
|
|
if !ok || parent == "" {
|
||
|
|
return
|
||
|
|
}
|
||
|
|
id = parent
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func permissionToNode(perm *entity.Permission) *dom.PermissionTreeNode {
|
||
|
|
return &dom.PermissionTreeNode{
|
||
|
|
ID: perm.ID.Hex(),
|
||
|
|
Parent: perm.Parent,
|
||
|
|
Name: perm.Name,
|
||
|
|
HTTPMethods: perm.HTTPMethods,
|
||
|
|
HTTPPath: perm.HTTPPath,
|
||
|
|
Status: perm.Status,
|
||
|
|
Type: perm.Type,
|
||
|
|
}
|
||
|
|
}
|