package usecase import ( "code.30cm.net/digimon/app-cloudep-permission-server/pkg/domain/entity" "code.30cm.net/digimon/app-cloudep-permission-server/pkg/domain/permission" "sync" "go.mongodb.org/mongo-driver/bson/primitive" ) // PermissionTree 用來管理權限節點,包含快速查詢 map 與輔助 map(例如名稱對應的 ID 列表) type PermissionTree struct { // dummy root 節點 root *PermissionNode // permission id => node nodes map[string]*PermissionNode // permission name => permission id names map[string][]string mu sync.RWMutex // 保護樹的並發存取 } type PermissionNode struct { Data entity.Permission Parent *PermissionNode Children []*PermissionNode } // GeneratePermissionTree 根據扁平權限資料建立樹,並掛在 dummy root 下 func GeneratePermissionTree(permissions []entity.Permission) *PermissionTree { tree := &PermissionTree{ nodes: make(map[string]*PermissionNode), names: make(map[string][]string), } // 1. 建立所有節點 for _, perm := range permissions { node := &PermissionNode{ Data: perm, Children: []*PermissionNode{}, } tree.nodes[perm.ID.Hex()] = node tree.names[perm.Name] = append(tree.names[perm.Name], perm.ID.Hex()) } // 2. 建立 dummy root 節點 tree.root = &PermissionNode{ Data: entity.Permission{ID: primitive.NewObjectID(), Name: "root"}, Children: []*PermissionNode{}, } // 3. 建立父子連結:若找不到父節點或 Parent 為 0,則掛在 dummy root 下 for _, node := range tree.nodes { if node.Data.Parent == "" { node.Parent = tree.root tree.root.Children = append(tree.root.Children, node) } else if parent, ok := tree.nodes[node.Data.Parent]; ok { node.Parent = parent parent.Children = append(parent.Children, node) } else { // 若父節點不存在,預設掛在 dummy root 下 node.Parent = tree.root tree.root.Children = append(tree.root.Children, node) } } return tree } // getNode 輔助函數:根據 ID 從樹中查找節點 func (tree *PermissionTree) getNode(id string) *PermissionNode { tree.mu.RLock() defer tree.mu.RUnlock() return tree.nodes[id] } func (tree *PermissionTree) put(node entity.Permission) { parentNode := tree.getNode(node.Parent) if parentNode == nil { parentNode = tree.root } thisNode := &PermissionNode{ Data: node, Parent: parentNode, Children: make([]*PermissionNode, 0), } parentNode.Children = append(parentNode.Children, thisNode) tree.names[node.Name] = append(tree.names[node.Name], node.ID.Hex()) tree.nodes[node.ID.Hex()] = thisNode } // filterOpenNodes 走訪整棵樹,列出有被打開的節點(父節點沒開,則底下的都不會開) // 如果某個節點為非葉節點,則會檢查其子節點是否有啟用,否則該節點不會被展開。 // [permissionID] entity.Permission func (tree *PermissionTree) filterOpenNodes() (map[string]entity.Permission, error) { tree.mu.RLock() defer tree.mu.RUnlock() result := make(map[string]entity.Permission) // dfs 為內部閉包,可存取 result // 返回值 bool 表示目前節點或其子孫中是否存在有效 open 節點 var dfs func(node *PermissionNode) bool dfs = func(node *PermissionNode) bool { // 若本身狀態非 open,則整個分支不展開 if node.Data.Status != permission.Open { return false } // 節點本身是 open,不論子節點狀態如何,先將該節點加入結果 result[node.Data.ID.Hex()] = node.Data // 遞迴處理子節點 for _, child := range node.Children { dfs(child) } return true } // 從 dummy root 的 Children 開始走訪(dummy root 本身不納入結果) for _, child := range tree.root.Children { dfs(child) } return result, nil } //// getFullParentPermissionIDs //// 根據傳入的權限狀態 (Permissions) 回傳完整的權限 ID 列表,包含所有祖先。 //// 如果某個節點為非葉節點,則會檢查其子節點是否有啟用,否則該節點不會被展開。 //func (tree *PermissionTree) getFullParentPermissionIDs(permissions permission.Permissions) ([]string, error) { // tree.mu.RLock() // defer tree.mu.RUnlock() // // exist := make(map[string]bool) // var ids []string // // for name, status := range permissions { // if status != permission.OpenPermission { // continue // } // idList, ok := tree.nameToIDs[name] // if !ok { // return nil, NotFoundError // } // for _, pid := range idList { // node, exists := tree.nodes[pid] // if !exists || node == nil { // return nil, NotFoundError // } // // 如果為父節點,檢查其子節點是否有啟用,若都關閉則不展開 // if len(node.Children) > 0 { // var childOpen bool // for _, child := range node.Children { // if childStatus, ok := permissions[child.Data.Name]; ok && childStatus == permission.OpenPermission { // childOpen = true // break // } // } // if !childOpen { // continue // } // } // // 將該節點及所有祖先(直到 dummy root,不包括 dummy root)加入結果 // for cur := node; cur != nil && cur.Data.Name != "root"; cur = cur.Parent { // if !exist[cur.Data.ID.Hex()] { // ids = append(ids, cur.Data.ID.Hex()) // exist[cur.Data.ID.Hex()] = true // } // } // } // } // // return ids, nil //} //// getFullParentPermissionStatus //// 根據傳入的權限狀態 (Permissions) 回傳完整的權限狀態,包含所有祖先的名稱設為啟用。 //func (tree *PermissionTree) getFullParentPermissionStatus(permissions permission.Permissions) (permission.Permissions, error) { // tree.mu.RLock() // defer tree.mu.RUnlock() // // result := make(permission.Permissions) // exist := make(map[string]bool) // // for name, status := range permissions { // if status != permission.OpenPermission { // continue // } // idList, ok := tree.nameToIDs[name] // if !ok { // return nil, NotFoundError // } // for _, pid := range idList { // node, exists := tree.nodes[pid] // if !exists || node == nil { // return nil, NotFoundError // } // // 將該節點及所有祖先標記為啟用 // for cur := node; cur != nil && cur.Data.Name != "root"; cur = cur.Parent { // if !exist[cur.Data.ID.Hex()] { // result[cur.Data.Name] = permission.OpenPermission // exist[cur.Data.ID.Hex()] = true // } // } // } // } // // return result, nil //} // //// getFullParentPermission //// 根據角色權限 (RolePermission) 列表,回傳完整的權限狀態(名稱->狀態),包含所有祖先 //func (tree *PermissionTree) getFullParentPermission(rolePermissions []entity.RolePermission) permission.Permissions { // tree.mu.RLock() // defer tree.mu.RUnlock() // // result := make(permission.Permissions) // for _, rp := range rolePermissions { // node, ok := tree.nodes[rp.PermissionID] // if !ok || node == nil { // continue // } // // 將該節點及所有祖先設為啟用 // for cur := node; cur != nil && cur.Data.Name != "root"; cur = cur.Parent { // result[cur.Data.Name] = permission.OpenPermission // } // } // return result //}