231 lines
6.9 KiB
Go
231 lines
6.9 KiB
Go
package usecase
|
||
|
||
import (
|
||
"sync"
|
||
|
||
"code.30cm.net/digimon/app-cloudep-permission-server/pkg/domain/entity"
|
||
"code.30cm.net/digimon/app-cloudep-permission-server/pkg/domain/permission"
|
||
|
||
"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
|
||
//}
|